tombstoned: allow intercepts for java traces.
All intercept requests and crash dump requests must now specify a
dump_type, which can be one of kDebuggerdNativeBacktrace,
kDebuggerdTombstone or kDebuggerdJavaBacktrace. Each process can have
only one outstanding intercept registered at a time.
There's only one non-trivial change in this changeset; and that is
to crash_dump. We now pass the type of dump via a command line
argument instead of inferring it from the (resent) signal, this allows
us to connect to tombstoned before we wait for the signal as the
protocol requires.
Test: debuggerd_test
Change-Id: I189b215acfecd08ac52ab29117e3465da00e3a37
diff --git a/debuggerd/tombstoned/tombstoned.cpp b/debuggerd/tombstoned/tombstoned.cpp
index 05df9f2..0a9f000 100644
--- a/debuggerd/tombstoned/tombstoned.cpp
+++ b/debuggerd/tombstoned/tombstoned.cpp
@@ -35,6 +35,7 @@
#include <cutils/sockets.h>
#include "debuggerd/handler.h"
+#include "dump_type.h"
#include "protocol.h"
#include "util.h"
@@ -52,10 +53,10 @@
struct Crash;
-class CrashType {
+class CrashQueue {
public:
- CrashType(const std::string& dir_path, const std::string& file_name_prefix, size_t max_artifacts,
- size_t max_concurrent_dumps)
+ CrashQueue(const std::string& dir_path, const std::string& file_name_prefix, size_t max_artifacts,
+ size_t max_concurrent_dumps)
: file_name_prefix_(file_name_prefix),
dir_path_(dir_path),
dir_fd_(open(dir_path.c_str(), O_DIRECTORY | O_RDONLY | O_CLOEXEC)),
@@ -114,8 +115,8 @@
void on_crash_completed() { --num_concurrent_dumps_; }
- static CrashType* const tombstone;
- static CrashType* const java_trace;
+ static CrashQueue* const tombstone;
+ static CrashQueue* const java_trace;
private:
void find_oldest_artifact() {
@@ -158,19 +159,19 @@
std::deque<Crash*> queued_requests_;
- DISALLOW_COPY_AND_ASSIGN(CrashType);
+ DISALLOW_COPY_AND_ASSIGN(CrashQueue);
};
// Whether java trace dumps are produced via tombstoned.
static constexpr bool kJavaTraceDumpsEnabled = false;
-/* static */ CrashType* const CrashType::tombstone =
- new CrashType("/data/tombstones", "tombstone_" /* file_name_prefix */, 10 /* max_artifacts */,
- 1 /* max_concurrent_dumps */);
+/* static */ CrashQueue* const CrashQueue::tombstone =
+ new CrashQueue("/data/tombstones", "tombstone_" /* file_name_prefix */, 10 /* max_artifacts */,
+ 1 /* max_concurrent_dumps */);
-/* static */ CrashType* const CrashType::java_trace =
- (kJavaTraceDumpsEnabled ? new CrashType("/data/anr", "anr_" /* file_name_prefix */,
- 64 /* max_artifacts */, 4 /* max_concurrent_dumps */)
+/* static */ CrashQueue* const CrashQueue::java_trace =
+ (kJavaTraceDumpsEnabled ? new CrashQueue("/data/anr", "anr_" /* file_name_prefix */,
+ 64 /* max_artifacts */, 4 /* max_concurrent_dumps */)
: nullptr);
// Ownership of Crash is a bit messy.
@@ -183,10 +184,17 @@
pid_t crash_pid;
event* crash_event = nullptr;
- // Not owned by |Crash|.
- CrashType* crash_type = nullptr;
+ DebuggerdDumpType crash_type;
};
+static CrashQueue* get_crash_queue(const Crash* crash) {
+ if (crash->crash_type == kDebuggerdJavaBacktrace) {
+ return CrashQueue::java_trace;
+ }
+
+ return CrashQueue::tombstone;
+}
+
// Forward declare the callbacks so they can be placed in a sensible order.
static void crash_accept_cb(evconnlistener* listener, evutil_socket_t sockfd, sockaddr*, int, void*);
static void crash_request_cb(evutil_socket_t sockfd, short ev, void* arg);
@@ -194,10 +202,8 @@
static void perform_request(Crash* crash) {
unique_fd output_fd;
- // Note that java traces are not interceptible.
- if ((crash->crash_type == CrashType::java_trace) ||
- !intercept_manager->GetIntercept(crash->crash_pid, &output_fd)) {
- output_fd = crash->crash_type->get_output_fd();
+ if (!intercept_manager->GetIntercept(crash->crash_pid, crash->crash_type, &output_fd)) {
+ output_fd = get_crash_queue(crash)->get_output_fd();
}
TombstonedCrashPacket response = {
@@ -220,7 +226,7 @@
event_add(crash->crash_event, &timeout);
}
- crash->crash_type->on_crash_started();
+ get_crash_queue(crash)->on_crash_started();
return;
fail:
@@ -228,22 +234,22 @@
}
static void crash_accept_cb(evconnlistener* listener, evutil_socket_t sockfd, sockaddr*, int,
- void* crash_type) {
+ void*) {
event_base* base = evconnlistener_get_base(listener);
Crash* crash = new Crash();
+ // TODO: Make sure that only java crashes come in on the java socket
+ // and only native crashes on the native socket.
struct timeval timeout = { 1, 0 };
event* crash_event = event_new(base, sockfd, EV_TIMEOUT | EV_READ, crash_request_cb, crash);
crash->crash_fd.reset(sockfd);
crash->crash_event = crash_event;
- crash->crash_type = static_cast<CrashType*>(crash_type);
event_add(crash_event, &timeout);
}
static void crash_request_cb(evutil_socket_t sockfd, short ev, void* arg) {
ssize_t rc;
Crash* crash = static_cast<Crash*>(arg);
- CrashType* type = crash->crash_type;
TombstonedCrashPacket request = {};
@@ -271,7 +277,13 @@
goto fail;
}
- if (type == CrashType::tombstone) {
+ crash->crash_type = request.packet.dump_request.dump_type;
+ if (crash->crash_type < 0 || crash->crash_type > kDebuggerdAnyIntercept) {
+ LOG(WARNING) << "unexpected crash dump type: " << crash->crash_type;
+ goto fail;
+ }
+
+ if (crash->crash_type != kDebuggerdJavaBacktrace) {
crash->crash_pid = request.packet.dump_request.pid;
} else {
// Requests for java traces are sent from untrusted processes, so we
@@ -290,7 +302,7 @@
LOG(INFO) << "received crash request for pid " << crash->crash_pid;
- if (type->maybe_enqueue_crash(crash)) {
+ if (get_crash_queue(crash)->maybe_enqueue_crash(crash)) {
LOG(INFO) << "enqueueing crash request for pid " << crash->crash_pid;
} else {
perform_request(crash);
@@ -307,7 +319,7 @@
Crash* crash = static_cast<Crash*>(arg);
TombstonedCrashPacket request = {};
- crash->crash_type->on_crash_completed();
+ get_crash_queue(crash)->on_crash_completed();
if ((ev & EV_READ) == 0) {
goto fail;
@@ -330,11 +342,11 @@
}
fail:
- CrashType* type = crash->crash_type;
+ CrashQueue* queue = get_crash_queue(crash);
delete crash;
// If there's something queued up, let them proceed.
- type->maybe_dequeue_crashes(perform_request);
+ queue->maybe_dequeue_crashes(perform_request);
}
int main(int, char* []) {
@@ -366,7 +378,7 @@
intercept_manager = new InterceptManager(base, intercept_socket);
evconnlistener* tombstone_listener = evconnlistener_new(
- base, crash_accept_cb, CrashType::tombstone, -1, LEV_OPT_CLOSE_ON_FREE, crash_socket);
+ base, crash_accept_cb, CrashQueue::tombstone, -1, LEV_OPT_CLOSE_ON_FREE, crash_socket);
if (!tombstone_listener) {
LOG(FATAL) << "failed to create evconnlistener for tombstones.";
}
@@ -379,7 +391,7 @@
evutil_make_socket_nonblocking(java_trace_socket);
evconnlistener* java_trace_listener = evconnlistener_new(
- base, crash_accept_cb, CrashType::java_trace, -1, LEV_OPT_CLOSE_ON_FREE, java_trace_socket);
+ base, crash_accept_cb, CrashQueue::java_trace, -1, LEV_OPT_CLOSE_ON_FREE, java_trace_socket);
if (!java_trace_listener) {
LOG(FATAL) << "failed to create evconnlistener for java traces.";
}