summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/Android.bp1
-rw-r--r--runtime/parsed_options.cc6
-rw-r--r--runtime/runtime.cc8
-rw-r--r--runtime/runtime.h8
-rw-r--r--runtime/runtime_options.def2
-rw-r--r--runtime/signal_catcher.cc93
-rw-r--r--runtime/signal_catcher.h26
-rw-r--r--test/987-stack-trace-dumping/expected.txt0
-rw-r--r--test/987-stack-trace-dumping/info.txt0
-rwxr-xr-xtest/987-stack-trace-dumping/run18
-rw-r--r--test/987-stack-trace-dumping/src/Main.java60
-rw-r--r--test/knownfailures.json3
12 files changed, 88 insertions, 137 deletions
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 8ee5498115..aa7dc65871 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -352,6 +352,7 @@ cc_defaults {
"libdl",
// For android::FileMap used by libziparchive.
"libutils",
+ "libtombstoned_client"
],
static_libs: [
// ZipArchive support, the order matters here to get all symbols.
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index fc91efa6ac..ef4957c0ba 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -238,9 +238,9 @@ std::unique_ptr<RuntimeParser> ParsedOptions::MakeParser(bool ignore_unrecognize
.Define("-Xlockprofthreshold:_")
.WithType<unsigned int>()
.IntoKey(M::LockProfThreshold)
- .Define("-Xstacktracedir:_")
- .WithType<std::string>()
- .IntoKey(M::StackTraceDir)
+ .Define("-Xusetombstonedtraces")
+ .WithValue(true)
+ .IntoKey(M::UseTombstonedTraces)
.Define("-Xstacktracefile:_")
.WithType<std::string>()
.IntoKey(M::StackTraceFile)
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index c46bd8d2b9..968f02a359 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -834,7 +834,7 @@ void Runtime::InitNonZygoteOrPostFork(
void Runtime::StartSignalCatcher() {
if (!is_zygote_) {
- signal_catcher_ = new SignalCatcher(stack_trace_dir_, stack_trace_file_);
+ signal_catcher_ = new SignalCatcher(stack_trace_file_, use_tombstoned_traces_);
}
}
@@ -1069,7 +1069,11 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
abort_ = runtime_options.GetOrDefault(Opt::HookAbort);
default_stack_size_ = runtime_options.GetOrDefault(Opt::StackSize);
- stack_trace_dir_ = runtime_options.ReleaseOrDefault(Opt::StackTraceDir);
+ use_tombstoned_traces_ = runtime_options.GetOrDefault(Opt::UseTombstonedTraces);
+#if !defined(ART_TARGET_ANDROID)
+ CHECK(!use_tombstoned_traces_)
+ << "-Xusetombstonedtraces is only supported in an Android environment";
+#endif
stack_trace_file_ = runtime_options.ReleaseOrDefault(Opt::StackTraceFile);
compiler_executable_ = runtime_options.ReleaseOrDefault(Opt::Compiler);
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 2e3b8d7bae..483d25593f 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -783,7 +783,13 @@ class Runtime {
ClassLinker* class_linker_;
SignalCatcher* signal_catcher_;
- std::string stack_trace_dir_;
+
+ // If true, the runtime will connect to tombstoned via a socket to
+ // request an open file descriptor to write its traces to.
+ bool use_tombstoned_traces_;
+
+ // Location to which traces must be written on SIGQUIT. Only used if
+ // tombstoned_traces_ == false.
std::string stack_trace_file_;
std::unique_ptr<JavaVMExt> java_vm_;
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index 77132a8bae..cfc681f23f 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -100,7 +100,7 @@ RUNTIME_OPTIONS_KEY (Unit, NoSigChain)
RUNTIME_OPTIONS_KEY (Unit, ForceNativeBridge)
RUNTIME_OPTIONS_KEY (LogVerbosity, Verbose)
RUNTIME_OPTIONS_KEY (unsigned int, LockProfThreshold)
-RUNTIME_OPTIONS_KEY (std::string, StackTraceDir)
+RUNTIME_OPTIONS_KEY (bool, UseTombstonedTraces, false)
RUNTIME_OPTIONS_KEY (std::string, StackTraceFile)
RUNTIME_OPTIONS_KEY (Unit, MethodTrace)
RUNTIME_OPTIONS_KEY (std::string, MethodTraceFile, "/data/misc/trace/method-trace-file.bin")
diff --git a/runtime/signal_catcher.cc b/runtime/signal_catcher.cc
index faea7b3821..e3dfc74628 100644
--- a/runtime/signal_catcher.cc
+++ b/runtime/signal_catcher.cc
@@ -42,6 +42,10 @@
#include "thread_list.h"
#include "utils.h"
+#if defined(ART_TARGET_ANDROID)
+#include "tombstoned/tombstoned.h"
+#endif
+
namespace art {
static void DumpCmdLine(std::ostream& os) {
@@ -66,13 +70,19 @@ static void DumpCmdLine(std::ostream& os) {
#endif
}
-SignalCatcher::SignalCatcher(const std::string& stack_trace_dir,
- const std::string& stack_trace_file)
- : stack_trace_dir_(stack_trace_dir),
- stack_trace_file_(stack_trace_file),
+SignalCatcher::SignalCatcher(const std::string& stack_trace_file,
+ bool use_tombstoned_stack_trace_fd)
+ : stack_trace_file_(stack_trace_file),
+ use_tombstoned_stack_trace_fd_(use_tombstoned_stack_trace_fd),
lock_("SignalCatcher lock"),
cond_("SignalCatcher::cond_", lock_),
thread_(nullptr) {
+#if !defined(ART_TARGET_ANDROID)
+ // We're not running on Android, so we can't communicate with tombstoned
+ // to ask for an open file.
+ CHECK(!use_tombstoned_stack_trace_fd_);
+#endif
+
SetHaltFlag(false);
// Create a raw pthread; its start routine will attach to the runtime.
@@ -103,62 +113,65 @@ bool SignalCatcher::ShouldHalt() {
return halt_;
}
-std::string SignalCatcher::GetStackTraceFileName() {
- if (!stack_trace_dir_.empty()) {
- // We'll try a maximum of ten times (arbitrarily selected) to create a file
- // with a unique name, seeding the pseudo random generator each time.
- //
- // If this doesn't work, give up and log to stdout. Note that we could try
- // indefinitely, but that would make problems in this code harder to detect
- // since we'd be spinning in the signal catcher thread.
- static constexpr uint32_t kMaxRetries = 10;
-
- for (uint32_t i = 0; i < kMaxRetries; ++i) {
- std::srand(NanoTime());
- // Sample output for PID 1234 : /data/anr/anr-pid1234-cafeffee.txt
- const std::string file_name = android::base::StringPrintf(
- "%s/anr-pid%" PRId32 "-%08" PRIx32 ".txt",
- stack_trace_dir_.c_str(),
- static_cast<int32_t>(getpid()),
- static_cast<uint32_t>(std::rand()));
-
- if (!OS::FileExists(file_name.c_str())) {
- return file_name;
- }
- }
+bool SignalCatcher::OpenStackTraceFile(android::base::unique_fd* tombstone_fd,
+ android::base::unique_fd* output_fd) {
+ if (use_tombstoned_stack_trace_fd_) {
+#if defined(ART_TARGET_ANDROID)
+ return tombstoned_connect(getpid(), tombstone_fd, output_fd, false /* is_native_crash */);
+#else
+ UNUSED(tombstone_fd);
+ UNUSED(output_fd);
+#endif
+ }
+
+ // The runtime is not configured to dump traces to a file, will LOG(INFO)
+ // instead.
+ if (stack_trace_file_.empty()) {
+ return false;
+ }
- LOG(ERROR) << "Unable to obtain stack trace filename at path : " << stack_trace_dir_;
- return "";
+ int fd = open(stack_trace_file_.c_str(), O_APPEND | O_CREAT | O_WRONLY, 0666);
+ if (fd == -1) {
+ PLOG(ERROR) << "Unable to open stack trace file '" << stack_trace_file_ << "'";
+ return false;
}
- return stack_trace_file_;
+ output_fd->reset(fd);
+ return true;
}
void SignalCatcher::Output(const std::string& s) {
- const std::string output_file = GetStackTraceFileName();
- if (output_file.empty()) {
+ android::base::unique_fd tombstone_fd;
+ android::base::unique_fd output_fd;
+ if (!OpenStackTraceFile(&tombstone_fd, &output_fd)) {
LOG(INFO) << s;
return;
}
ScopedThreadStateChange tsc(Thread::Current(), kWaitingForSignalCatcherOutput);
- int fd = open(output_file.c_str(), O_APPEND | O_CREAT | O_WRONLY, 0666);
- if (fd == -1) {
- PLOG(ERROR) << "Unable to open stack trace file '" << output_file << "'";
- return;
- }
- std::unique_ptr<File> file(new File(fd, output_file, true));
+
+ std::unique_ptr<File> file(new File(output_fd.release(), true /* check_usage */));
bool success = file->WriteFully(s.data(), s.size());
if (success) {
success = file->FlushCloseOrErase() == 0;
} else {
file->Erase();
}
+
+ const std::string output_path_msg = (use_tombstoned_stack_trace_fd_) ?
+ "[tombstoned]" : stack_trace_file_;
+
if (success) {
- LOG(INFO) << "Wrote stack traces to '" << output_file << "'";
+ LOG(INFO) << "Wrote stack traces to '" << output_path_msg << "'";
} else {
- PLOG(ERROR) << "Failed to write stack traces to '" << output_file << "'";
+ PLOG(ERROR) << "Failed to write stack traces to '" << output_path_msg << "'";
}
+
+#if defined(ART_TARGET_ANDROID)
+ if (!tombstoned_notify_completion(tombstone_fd)) {
+ LOG(WARNING) << "Unable to notify tombstoned of dump completion.";
+ }
+#endif
}
void SignalCatcher::HandleSigQuit() {
diff --git a/runtime/signal_catcher.h b/runtime/signal_catcher.h
index 4cd7a98795..8a2a7289de 100644
--- a/runtime/signal_catcher.h
+++ b/runtime/signal_catcher.h
@@ -17,6 +17,7 @@
#ifndef ART_RUNTIME_SIGNAL_CATCHER_H_
#define ART_RUNTIME_SIGNAL_CATCHER_H_
+#include "android-base/unique_fd.h"
#include "base/mutex.h"
namespace art {
@@ -32,15 +33,17 @@ class Thread;
*/
class SignalCatcher {
public:
- // If |stack_trace_dir| is non empty, traces will be written to a
- // unique file under that directory.
+ // If |use_tombstoned_stack_trace_fd| is |true|, traces will be
+ // written to a file descriptor provided by tombstoned. The process
+ // will communicate with tombstoned via a unix domain socket. This
+ // mode of stack trace dumping is only supported in an Android
+ // environment.
//
- // If |stack_trace_dir| is empty, and |stack_frace_file| is non-empty,
- // traces will be appended to |stack_trace_file|.
- //
- // If both are empty, all traces will be written to the log buffer.
- explicit SignalCatcher(const std::string& stack_trace_dir,
- const std::string& stack_trace_file);
+ // If false, all traces will be dumped to |stack_trace_file| if it's
+ // non-empty. If |stack_trace_file| is empty, all traces will be written
+ // to the log buffer.
+ SignalCatcher(const std::string& stack_trace_file,
+ const bool use_tombstoned_stack_trace_fd);
~SignalCatcher();
void HandleSigQuit() REQUIRES(!Locks::mutator_lock_, !Locks::thread_list_lock_,
@@ -51,15 +54,18 @@ class SignalCatcher {
// NO_THREAD_SAFETY_ANALYSIS for static function calling into member function with excludes lock.
static void* Run(void* arg) NO_THREAD_SAFETY_ANALYSIS;
- std::string GetStackTraceFileName();
+ // NOTE: We're using android::base::unique_fd here for easier
+ // interoperability with tombstoned client APIs.
+ bool OpenStackTraceFile(android::base::unique_fd* tombstone_fd,
+ android::base::unique_fd* output_fd);
void HandleSigUsr1();
void Output(const std::string& s);
void SetHaltFlag(bool new_value) REQUIRES(!lock_);
bool ShouldHalt() REQUIRES(!lock_);
int WaitForSignal(Thread* self, SignalSet& signals) REQUIRES(!lock_);
- std::string stack_trace_dir_;
std::string stack_trace_file_;
+ const bool use_tombstoned_stack_trace_fd_;
mutable Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
ConditionVariable cond_ GUARDED_BY(lock_);
diff --git a/test/987-stack-trace-dumping/expected.txt b/test/987-stack-trace-dumping/expected.txt
deleted file mode 100644
index e69de29bb2..0000000000
--- a/test/987-stack-trace-dumping/expected.txt
+++ /dev/null
diff --git a/test/987-stack-trace-dumping/info.txt b/test/987-stack-trace-dumping/info.txt
deleted file mode 100644
index e69de29bb2..0000000000
--- a/test/987-stack-trace-dumping/info.txt
+++ /dev/null
diff --git a/test/987-stack-trace-dumping/run b/test/987-stack-trace-dumping/run
deleted file mode 100755
index dee3e8ba04..0000000000
--- a/test/987-stack-trace-dumping/run
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/bash
-#
-# Copyright 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Ask for stack traces to be dumped to a file rather than to stdout.
-./default-run "$@" --set-stack-trace-dump-dir
diff --git a/test/987-stack-trace-dumping/src/Main.java b/test/987-stack-trace-dumping/src/Main.java
deleted file mode 100644
index d1e8a1b56b..0000000000
--- a/test/987-stack-trace-dumping/src/Main.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import java.io.File;
-
-public class Main {
- public static void main(String[] args) throws Exception {
- if (args.length != 3) {
- throw new AssertionError("Unexpected number of args: " + args.length);
- }
-
- if (!"--stack-trace-dir".equals(args[1])) {
- throw new AssertionError("Unexpected argument in position 1: " + args[1]);
- }
-
- // Send ourselves signal 3, which forces stack traces to be written to disk.
- android.system.Os.kill(android.system.Os.getpid(), 3);
-
- File[] files = null;
- final String stackTraceDir = args[2];
- for (int i = 0; i < 5; ++i) {
- // Give the signal handler some time to run and dump traces - up to a maximum
- // of 5 seconds. This is a kludge, but it's hard to do this without using things
- // like inotify / WatchService and the like.
- Thread.sleep(1000);
-
- files = (new File(stackTraceDir)).listFiles();
- if (files != null && files.length == 1) {
- break;
- }
- }
-
-
- if (files == null) {
- throw new AssertionError("Gave up waiting for traces: " + java.util.Arrays.toString(files));
- }
-
- final String fileName = files[0].getName();
- if (!fileName.startsWith("anr-pid")) {
- throw new AssertionError("Unexpected prefix: " + fileName);
- }
-
- if (!fileName.contains(String.valueOf(android.system.Os.getpid()))) {
- throw new AssertionError("File name does not contain process PID: " + fileName);
- }
- }
-}
diff --git a/test/knownfailures.json b/test/knownfailures.json
index 4b44df7958..96c2967f86 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -651,8 +651,7 @@
"969-iface-super",
"981-dedup-original-dex",
"984-obsolete-invoke",
- "985-re-obsolete",
- "987-stack-trace-dumping"
+ "985-re-obsolete"
],
"description": "The tests above fail with --build-with-javac-dx.",
"env_vars": {"ANDROID_COMPILE_WITH_JACK": "false"},