ART: Print INTERNAL_FATAL Log messages immediately

To diagnose some problems, print out messages sent to Severity level
INTERNAL_FATAL immediately. This avoids the buffering we do.

Bug: 18933933
Change-Id: I3e536ae2e78560eb561d0b873fb4e88b9495ebbf
diff --git a/runtime/base/logging.cc b/runtime/base/logging.cc
index 7c2ef71..f3e0918 100644
--- a/runtime/base/logging.cc
+++ b/runtime/base/logging.cc
@@ -16,6 +16,7 @@
 
 #include "logging.h"
 
+#include <iostream>
 #include <limits>
 #include <sstream>
 
@@ -43,6 +44,19 @@
 static std::unique_ptr<std::string> gProgramInvocationName;
 static std::unique_ptr<std::string> gProgramInvocationShortName;
 
+// Print INTERNAL_FATAL messages directly instead of at destruction time. This only works on the
+// host right now: for the device, a stream buf collating output into lines and calling LogLine or
+// lower-level logging is necessary.
+#ifdef HAVE_ANDROID_OS
+static constexpr bool kPrintInternalFatalDirectly = false;
+#else
+static constexpr bool kPrintInternalFatalDirectly = !kIsTargetBuild;
+#endif
+
+static bool PrintDirectly(LogSeverity severity) {
+  return kPrintInternalFatalDirectly && severity == INTERNAL_FATAL;
+}
+
 const char* GetCmdLine() {
   return (gCmdLine.get() != nullptr) ? gCmdLine->c_str() : nullptr;
 }
@@ -170,31 +184,39 @@
 
 LogMessage::LogMessage(const char* file, unsigned int line, LogSeverity severity, int error)
   : data_(new LogMessageData(file, line, severity, error)) {
+  if (PrintDirectly(severity)) {
+    static const char* log_characters = "VDIWEFF";
+    CHECK_EQ(strlen(log_characters), INTERNAL_FATAL + 1U);
+    stream() << ProgramInvocationShortName() << " " << log_characters[static_cast<size_t>(severity)]
+             << " " << getpid() << " " << ::art::GetTid() << " " << file << ":" <<  line << "]";
+  }
 }
 LogMessage::~LogMessage() {
-  if (data_->GetSeverity() < gMinimumLogSeverity) {
-    return;  // No need to format something we're not going to output.
-  }
+  if (!PrintDirectly(data_->GetSeverity())) {
+    if (data_->GetSeverity() < gMinimumLogSeverity) {
+      return;  // No need to format something we're not going to output.
+    }
 
-  // Finish constructing the message.
-  if (data_->GetError() != -1) {
-    data_->GetBuffer() << ": " << strerror(data_->GetError());
-  }
-  std::string msg(data_->ToString());
+    // Finish constructing the message.
+    if (data_->GetError() != -1) {
+      data_->GetBuffer() << ": " << strerror(data_->GetError());
+    }
+    std::string msg(data_->ToString());
 
-  // Do the actual logging with the lock held.
-  {
-    MutexLock mu(Thread::Current(), *Locks::logging_lock_);
-    if (msg.find('\n') == std::string::npos) {
-      LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), msg.c_str());
-    } else {
-      msg += '\n';
-      size_t i = 0;
-      while (i < msg.size()) {
-        size_t nl = msg.find('\n', i);
-        msg[nl] = '\0';
-        LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), &msg[i]);
-        i = nl + 1;
+    // Do the actual logging with the lock held.
+    {
+      MutexLock mu(Thread::Current(), *Locks::logging_lock_);
+      if (msg.find('\n') == std::string::npos) {
+        LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), msg.c_str());
+      } else {
+        msg += '\n';
+        size_t i = 0;
+        while (i < msg.size()) {
+          size_t nl = msg.find('\n', i);
+          msg[nl] = '\0';
+          LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), &msg[i]);
+          i = nl + 1;
+        }
       }
     }
   }
@@ -206,6 +228,9 @@
 }
 
 std::ostream& LogMessage::stream() {
+  if (PrintDirectly(data_->GetSeverity())) {
+    return std::cerr;
+  }
   return data_->GetBuffer();
 }