Plumb tombstoned connections through PALette.

This removes APEX internal dependencies on libtombstoned_client and
libcutils.

Test: art/build/apex/runtests.sh
Test: adb shell killall -QUIT system_server; check tombstoned report in /data/anr
Test: Make /data nearly full; adb shell killall -QUIT system_server; check
  that the report in /data/anr has zero length and that the stack traces are
  sent to logcat instead
Bug: 130025619
Change-Id: I93dae3729c0e4de9e32b942e6c85915b56d8114a
diff --git a/build/apex/art_apex_test.py b/build/apex/art_apex_test.py
index b93a705..4fc102a 100755
--- a/build/apex/art_apex_test.py
+++ b/build/apex/art_apex_test.py
@@ -450,9 +450,6 @@
     self._checker.check_optional_native_library('libclang_rt.hwasan*')
     self._checker.check_optional_native_library('libclang_rt.ubsan*')
 
-    # TODO(b/130025619): Get rid of this dependency.
-    self._checker.check_native_library('libcutils')
-
 
 class ReleaseTargetChecker:
   def __init__(self, checker):
@@ -497,7 +494,6 @@
     self._checker.check_native_library('libicui18n')
     self._checker.check_native_library('libicuuc')
     self._checker.check_native_library('libpac')
-    self._checker.check_native_library('libtombstoned_client')
     self._checker.check_native_library('libz')
 
     # TODO(b/124293228): Cuttlefish puts ARM libs in a lib/arm subdirectory.
diff --git a/libartpalette/Android.bp b/libartpalette/Android.bp
index 3e7354b..75bf97c 100644
--- a/libartpalette/Android.bp
+++ b/libartpalette/Android.bp
@@ -32,9 +32,11 @@
           srcs: ["system/palette_android.cc",],
           header_libs: ["libbase_headers"],
           shared_libs: [
+            "libbase",
             "libcutils",
             "liblog",
             "libprocessgroup",
+            "libtombstoned_client",
           ],
         },
         host: {
diff --git a/libartpalette/apex/palette.cc b/libartpalette/apex/palette.cc
index 0b391f8..1821a17 100644
--- a/libartpalette/apex/palette.cc
+++ b/libartpalette/apex/palette.cc
@@ -125,6 +125,11 @@
   return m(tid, java_priority);
 }
 
+enum PaletteStatus PaletteTombstonedMessage(/*in*/const char* msg, size_t msg_len) {
+  PaletteTombstonedMessageMethod m = PaletteLoader::Instance().GetPaletteTombstonedMessageMethod();
+  return m(msg, msg_len);
+}
+
 enum PaletteStatus PaletteTraceEnabled(/*out*/int32_t* enabled) {
   PaletteTraceEnabledMethod m = PaletteLoader::Instance().GetPaletteTraceEnabledMethod();
   return m(enabled);
diff --git a/libartpalette/include/palette/palette_method_list.h b/libartpalette/include/palette/palette_method_list.h
index dc4ec52..3e730fd 100644
--- a/libartpalette/include/palette/palette_method_list.h
+++ b/libartpalette/include/palette/palette_method_list.h
@@ -17,6 +17,7 @@
 #ifndef ART_LIBARTPALETTE_INCLUDE_PALETTE_PALETTE_METHOD_LIST_H_
 #define ART_LIBARTPALETTE_INCLUDE_PALETTE_PALETTE_METHOD_LIST_H_
 
+#include <stddef.h>
 #include <stdint.h>
 
 // Methods in version 1 API
@@ -24,6 +25,7 @@
   M(PaletteGetVersion, /*out*/int32_t* version)                             \
   M(PaletteSchedSetPriority, int32_t tid, int32_t java_priority)            \
   M(PaletteSchedGetPriority, int32_t tid, /*out*/int32_t* java_priority)    \
+  M(PaletteTombstonedMessage, const char* msg, size_t msg_len)              \
   M(PaletteTraceEnabled, /*out*/int32_t* enabled)                           \
   M(PaletteTraceBegin, const char* name)                                    \
   M(PaletteTraceEnd)                                                        \
diff --git a/libartpalette/libartpalette.map.txt b/libartpalette/libartpalette.map.txt
index 0920835..78b33ac 100644
--- a/libartpalette/libartpalette.map.txt
+++ b/libartpalette/libartpalette.map.txt
@@ -20,6 +20,7 @@
     PaletteGetVersion;
     PaletteSchedSetPriority;
     PaletteSchedGetPriority;
+    PaletteTombstonedMessage;
     PaletteTraceEnabled;
     PaletteTraceBegin;
     PaletteTraceEnd;
diff --git a/libartpalette/system/palette_android.cc b/libartpalette/system/palette_android.cc
index aed3862..801f334 100644
--- a/libartpalette/system/palette_android.cc
+++ b/libartpalette/system/palette_android.cc
@@ -25,11 +25,13 @@
 
 #include <mutex>
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/macros.h>
 #include <cutils/sched_policy.h>
 #include <cutils/trace.h>
 #include <log/event_tag_map.h>
+#include <tombstoned/tombstoned.h>
 #include <utils/Thread.h>
 
 #include "palette_system.h"
@@ -104,6 +106,44 @@
   return PaletteStatus::kOkay;
 }
 
+enum PaletteStatus PaletteTombstonedMessage(/*in*/const char* msg, size_t msg_len) {
+  android::base::unique_fd tombstone_fd;
+  android::base::unique_fd output_fd;
+  if (!tombstoned_connect(getpid(), &tombstone_fd, &output_fd, kDebuggerdJavaBacktrace)) {
+    return PaletteStatus::kCheckErrno;
+  }
+
+  bool success = true;
+  if (!android::base::WriteFully(output_fd, msg, msg_len)) {
+    LOG(ERROR) << "Failed to write tombstoned output: " << strerror(errno);
+    success = false;
+  } else if (TEMP_FAILURE_RETRY(fsync(output_fd)) == -1) {
+    LOG(ERROR) << "Failed to fsync tombstoned output: " << strerror(errno);
+    success = false;
+  } else if (close(output_fd.release()) == -1) {
+    // Shouldn't retry close after EINTR because the fd has been closed anyway,
+    // but don't count it as a failure either.
+    if (errno != EINTR) {
+      LOG(ERROR) << "Failed to close tombstoned output: " << strerror(errno);
+      success = false;
+    }
+  }
+
+  if (!success) {
+    int saved_errno = errno;
+    TEMP_FAILURE_RETRY(ftruncate(output_fd, 0));
+    TEMP_FAILURE_RETRY(fsync(output_fd));
+    close(output_fd.release());
+    errno = saved_errno;
+  }
+
+  if (!tombstoned_notify_completion(tombstone_fd)) {
+    success = false;
+  }
+
+  return success ? PaletteStatus::kOkay : PaletteStatus::kCheckErrno;
+}
+
 enum PaletteStatus PaletteTraceEnabled(/*out*/int32_t* enabled) {
   *enabled = (ATRACE_ENABLED() != 0) ? 1 : 0;
   return PaletteStatus::kOkay;
diff --git a/libartpalette/system/palette_fake.cc b/libartpalette/system/palette_fake.cc
index 0961e77..07a54df 100644
--- a/libartpalette/system/palette_fake.cc
+++ b/libartpalette/system/palette_fake.cc
@@ -52,6 +52,11 @@
   return PaletteStatus::kOkay;
 }
 
+enum PaletteStatus PaletteTombstonedMessage(/*in*/ const char* msg ATTRIBUTE_UNUSED,
+                                            size_t msg_len ATTRIBUTE_UNUSED) {
+  return PaletteStatus::kOkay;
+}
+
 enum PaletteStatus PaletteTraceEnabled(/*out*/int32_t* enabled) {
   *enabled = 0;
   return PaletteStatus::kOkay;
diff --git a/runtime/Android.bp b/runtime/Android.bp
index d73d93f..4dc1e5a 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -342,7 +342,6 @@
             ],
             shared_libs: [
                 "libdl_android",
-                "libtombstoned_client",
             ],
             static_libs: [
                 "libz",  // For adler32.
@@ -417,11 +416,6 @@
 
 libart_static_cc_defaults {
     name: "libart_static_base_defaults",
-    target: {
-        android: {
-            static_libs: ["libtombstoned_client_static"],
-        },
-    },
     static_libs: [
         "libartpalette",
         "libbacktrace",
diff --git a/runtime/signal_catcher.cc b/runtime/signal_catcher.cc
index 38ea9cc..1aa8487 100644
--- a/runtime/signal_catcher.cc
+++ b/runtime/signal_catcher.cc
@@ -16,10 +16,11 @@
 
 #include "signal_catcher.h"
 
+#include <csignal>
+#include <cstdlib>
+#include <cstring>
 #include <fcntl.h>
 #include <pthread.h>
-#include <signal.h>
-#include <stdlib.h>
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/types.h>
@@ -29,20 +30,15 @@
 
 #include <android-base/stringprintf.h>
 
-#if defined(ART_TARGET_ANDROID)
-#include <tombstoned/tombstoned.h>
-#endif
-
 #include "arch/instruction_set.h"
-#include "base/file_utils.h"
 #include "base/logging.h"  // For GetCmdLine.
 #include "base/os.h"
 #include "base/time_utils.h"
-#include "base/unix_file/fd_file.h"
 #include "base/utils.h"
 #include "class_linker.h"
 #include "gc/heap.h"
 #include "jit/profile_saver.h"
+#include "palette/palette.h"
 #include "runtime.h"
 #include "scoped_thread_state_change-inl.h"
 #include "signal_set.h"
@@ -109,30 +105,14 @@
 
 void SignalCatcher::Output(const std::string& s) {
 #if defined(ART_TARGET_ANDROID)
-  android::base::unique_fd tombstone_fd;
-  android::base::unique_fd output_fd;
-  if (!tombstoned_connect(getpid(), &tombstone_fd, &output_fd, kDebuggerdJavaBacktrace)) {
-    LOG(INFO) << s;
-    return;
-  }
-
   ScopedThreadStateChange tsc(Thread::Current(), kWaitingForSignalCatcherOutput);
-
-  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();
-  }
-
-  if (success) {
+  PaletteStatus status = PaletteTombstonedMessage(s.data(), s.size());
+  if (status == PaletteStatus::kOkay) {
     LOG(INFO) << "Wrote stack traces to tombstoned";
   } else {
-    PLOG(ERROR) << "Failed to write stack traces to tombstoned";
-  }
-  if (!tombstoned_notify_completion(tombstone_fd)) {
-    PLOG(WARNING) << "Unable to notify tombstoned of dump completion";
+    CHECK(status == PaletteStatus::kCheckErrno);
+    PLOG(ERROR) << "Failed to write stack traces to tombstoned: " << strerror(errno);
+    LOG(INFO) << s;
   }
 #else
   LOG(INFO) << s;