Implement -Xstacktracefile.

Change-Id: Ib6c73ddc6f0eaf8f8b731d450b87bda55589f857
diff --git a/src/runtime.cc b/src/runtime.cc
index be9c8fa..6148ae7 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -306,6 +306,8 @@
       parsed->jni_globals_max_ = ParseIntegerOrDie(option);
     } else if (option.starts_with("-Xlockprofthreshold:")) {
       parsed->lock_profiling_threshold_ = ParseIntegerOrDie(option);
+    } else if (option.starts_with("-Xstacktracefile:")) {
+      parsed->stack_trace_file_ = option.substr(strlen("-Xstacktracefile:")).data();
     } else if (option == "sensitiveThread") {
       parsed->hook_is_sensitive_thread_ = reinterpret_cast<bool (*)()>(options[i].second);
     } else if (option == "vfprintf") {
@@ -411,7 +413,7 @@
 
 void Runtime::StartSignalCatcher() {
   if (!is_zygote_) {
-    signal_catcher_ = new SignalCatcher;
+    signal_catcher_ = new SignalCatcher(stack_trace_file_);
   }
 }
 
@@ -469,6 +471,7 @@
   abort_ = options->hook_abort_;
 
   default_stack_size_ = options->stack_size_;
+  stack_trace_file_ = options->stack_trace_file_;
 
   monitor_list_ = new MonitorList;
   thread_list_ = new ThreadList(options->IsVerbose("thread"));
diff --git a/src/runtime.h b/src/runtime.h
index b29523e..44dfacf 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -58,6 +58,7 @@
     size_t stack_size_;
     size_t jni_globals_max_;
     size_t lock_profiling_threshold_;
+    std::string stack_trace_file_;
     bool (*hook_is_sensitive_thread_)();
     jint (*hook_vfprintf_)(FILE* stream, const char* format, va_list ap);
     void (*hook_exit_)(jint status);
@@ -254,6 +255,7 @@
   ClassLinker* class_linker_;
 
   SignalCatcher* signal_catcher_;
+  std::string stack_trace_file_;
 
   JavaVMExt* java_vm_;
 
diff --git a/src/signal_catcher.cc b/src/signal_catcher.cc
index a3e7bb1..851aab7 100644
--- a/src/signal_catcher.cc
+++ b/src/signal_catcher.cc
@@ -16,14 +16,19 @@
 
 #include "signal_catcher.h"
 
+#include <fcntl.h>
 #include <pthread.h>
 #include <signal.h>
 #include <stdlib.h>
+#include <sys/stat.h>
 #include <sys/time.h>
+#include <sys/types.h>
 #include <unistd.h>
 
 #include "class_linker.h"
+#include "file.h"
 #include "heap.h"
+#include "os.h"
 #include "runtime.h"
 #include "thread.h"
 #include "thread_list.h"
@@ -31,8 +36,11 @@
 
 namespace art {
 
-SignalCatcher::SignalCatcher()
-    : lock_("SignalCatcher lock"), cond_("SignalCatcher::cond_"), thread_(NULL) {
+SignalCatcher::SignalCatcher(const std::string& stack_trace_file)
+    : stack_trace_file_(stack_trace_file),
+      lock_("SignalCatcher lock"),
+      cond_("SignalCatcher::cond_"),
+      thread_(NULL) {
   SetHaltFlag(false);
 
   // Create a raw pthread; its start routine will attach to the runtime.
@@ -62,6 +70,27 @@
   return halt_;
 }
 
+void SignalCatcher::Output(const std::string& s) {
+  if (stack_trace_file_.empty()) {
+    LOG(INFO) << s;
+    return;
+  }
+
+  ScopedThreadStateChange tsc(Thread::Current(), Thread::kVmWait);
+  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;
+  }
+  UniquePtr<File> file(OS::FileFromFd(stack_trace_file_.c_str(), fd));
+  if (!file->WriteFully(s.data(), s.size())) {
+    PLOG(ERROR) << "Failed to write stack traces to '" << stack_trace_file_ << "'";
+  } else {
+    LOG(INFO) << "Wrote stack traces to '" << stack_trace_file_ << "'";
+  }
+  close(fd);
+}
+
 void SignalCatcher::HandleSigQuit() {
   Runtime* runtime = Runtime::Current();
   ThreadList* thread_list = runtime->GetThreadList();
@@ -92,11 +121,11 @@
     os << "/proc/self/maps:\n" << maps;
   }
 
-  os << "----- end " << getpid() << " -----";
+  os << "----- end " << getpid() << " -----\n";
 
   thread_list->ResumeAll();
 
-  LOG(INFO) << os.str();
+  Output(os.str());
 }
 
 void SignalCatcher::HandleSigUsr1() {
@@ -151,10 +180,10 @@
     LOG(INFO) << *signal_catcher->thread_ << ": reacting to signal " << signal_number;
     switch (signal_number) {
     case SIGQUIT:
-      HandleSigQuit();
+      signal_catcher->HandleSigQuit();
       break;
     case SIGUSR1:
-      HandleSigUsr1();
+      signal_catcher->HandleSigUsr1();
       break;
     default:
       LOG(ERROR) << "Unexpected signal %d" << signal_number;
diff --git a/src/signal_catcher.h b/src/signal_catcher.h
index 123b38f..5178b1a 100644
--- a/src/signal_catcher.h
+++ b/src/signal_catcher.h
@@ -31,18 +31,20 @@
  */
 class SignalCatcher {
  public:
-  SignalCatcher();
+  SignalCatcher(const std::string& stack_trace_file);
   ~SignalCatcher();
 
-  static void HandleSigQuit();
+  void HandleSigQuit();
 
  private:
   static void* Run(void* arg);
-  static void HandleSigUsr1();
 
+  void HandleSigUsr1();
+  void Output(const std::string& s);
   void SetHaltFlag(bool new_value);
   bool ShouldHalt();
 
+  std::string stack_trace_file_;
   mutable Mutex lock_;
   bool halt_;
   ConditionVariable cond_;