am ded2e5ac: debuggerd now notifies the Activity Manager about native crashes

* commit 'ded2e5acfcf0c705f08577d0ccb720bd5037f4ba':
  debuggerd now notifies the Activity Manager about native crashes
This commit is contained in:
Christopher Tate 2013-04-02 08:23:39 -07:00 committed by Android Git Automerger
commit a72f0ff083
6 changed files with 106 additions and 7 deletions

View File

@ -112,10 +112,11 @@ static void dump_thread(log_t* log, pid_t tid, ptrace_context_t* context, bool a
}
}
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);

View File

@ -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

View File

@ -314,7 +314,8 @@ static void handle_request(int fd) {
&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");

View File

@ -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 @@ static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal,
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 @@ static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal,
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 @@ static char* find_and_open_tombstone(int* fd)
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 @@ char* engrave_tombstone(pid_t pid, pid_t tid, int signal,
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;
}

View File

@ -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);
}

View File

@ -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;