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:
commit
a72f0ff083
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue