ART: Use file descriptors handed out by tombstoned for traces.

There no longer needs to be any logic in ART to generate file
names and create files. The test of file creation logic has
therefore been deleted.

Test: manual, tests in other components.
Bug: 32064548

Change-Id: I9bce6ddf3270839c40060d1287e79f9bd57d75aa
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 8ee5498..aa7dc65 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -352,6 +352,7 @@
                 "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 fc91efa..ef4957c 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -238,9 +238,9 @@
       .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 c46bd8d..968f02a 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -834,7 +834,7 @@
 
 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 @@
   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 2e3b8d7..483d255 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -783,7 +783,13 @@
   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 77132a8..cfc681f 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -100,7 +100,7 @@
 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 faea7b3..e3dfc74 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 @@
 #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 @@
   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;
-        }
-    }
-
-    LOG(ERROR) << "Unable to obtain stack trace filename at path : " << stack_trace_dir_;
-    return "";
+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
   }
 
-  return stack_trace_file_;
+  // The runtime is not configured to dump traces to a file, will LOG(INFO)
+  // instead.
+  if (stack_trace_file_.empty()) {
+    return false;
+  }
+
+  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;
+  }
+
+  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 4cd7a98..8a2a728 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 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 @@
   // 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 e69de29..0000000
--- 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 e69de29..0000000
--- 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 dee3e8b..0000000
--- 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 d1e8a1b..0000000
--- 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);
-        }
-    }
-}