Improving ART debugging and printing VmSize when OOM occurs

VmSize debugging information is added to quickly identify whether
the process address space or the system memory is insufficient

Test: 1 Manually trigger an OOM exception
      2 Checking whether the keyword VmSize exists in the OOM
      exception log
      3 art/test.py --host --64 -r

Signed-off-by: Wei Li <sirius.liwei@huawei.com>
Signed-off-by: Jinguang Dong <dongjinguang@huawei.com>

Change-Id: I0ea53f5136c06aba27712f95335ca722e7d30d95
diff --git a/libartbase/base/utils.cc b/libartbase/base/utils.cc
index 2242fe8..0f172fd 100644
--- a/libartbase/base/utils.cc
+++ b/libartbase/base/utils.cc
@@ -24,6 +24,7 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
+#include <fstream>
 #include <memory>
 
 #include "android-base/file.h"
@@ -213,4 +214,25 @@
   }
 }
 
+std::string GetProcessStatus(const char* key) {
+  // Build search pattern of key and separator.
+  std::string pattern(key);
+  pattern.push_back(':');
+
+  // Search for status lines starting with pattern.
+  std::ifstream fs("/proc/self/status");
+  std::string line;
+  while (std::getline(fs, line)) {
+    if (strncmp(pattern.c_str(), line.c_str(), pattern.size()) == 0) {
+      // Skip whitespace in matching line (if any).
+      size_t pos = line.find_first_not_of(" \t", pattern.size());
+      if (UNLIKELY(pos == std::string::npos)) {
+        break;
+      }
+      return std::string(line, pos);
+    }
+  }
+  return "<unknown>";
+}
+
 }  // namespace art
diff --git a/libartbase/base/utils.h b/libartbase/base/utils.h
index e6a0459..9c71055 100644
--- a/libartbase/base/utils.h
+++ b/libartbase/base/utils.h
@@ -216,6 +216,11 @@
   }
 }
 
+// Lookup value for a given key in /proc/self/status. Keys and values are separated by a ':' in
+// the status file. Returns value found on success and "<unknown>" if the key is not found or
+// there is an I/O error.
+std::string GetProcessStatus(const char* key);
+
 }  // namespace art
 
 #endif  // ART_LIBARTBASE_BASE_UTILS_H_
diff --git a/libartbase/base/utils_test.cc b/libartbase/base/utils_test.cc
index 892d1fd..9bd50c3 100644
--- a/libartbase/base/utils_test.cc
+++ b/libartbase/base/utils_test.cc
@@ -126,4 +126,12 @@
   EXPECT_EQ(BoundsCheckedCast<const uint64_t*>(buffer + 57, buffer, buffer_end), nullptr);
 }
 
+TEST_F(UtilsTest, GetProcessStatus) {
+  EXPECT_EQ("utils_test", GetProcessStatus("Name"));
+  EXPECT_EQ("R (running)", GetProcessStatus("State"));
+  EXPECT_EQ("<unknown>", GetProcessStatus("tate"));
+  EXPECT_EQ("<unknown>", GetProcessStatus("e"));
+  EXPECT_EQ("<unknown>", GetProcessStatus("Dummy"));
+}
+
 }  // namespace art
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 8a8f537..ae7a1a7 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -3147,8 +3147,10 @@
 }
 
 void Thread::ThrowOutOfMemoryError(const char* msg) {
-  LOG(WARNING) << StringPrintf("Throwing OutOfMemoryError \"%s\"%s",
-      msg, (tls32_.throwing_OutOfMemoryError ? " (recursive case)" : ""));
+  LOG(WARNING) << "Throwing OutOfMemoryError "
+               << '"' << msg << '"'
+               << " (VmSize " << GetProcessStatus("VmSize")
+               << (tls32_.throwing_OutOfMemoryError ? ", recursive case)" : ")");
   if (!tls32_.throwing_OutOfMemoryError) {
     tls32_.throwing_OutOfMemoryError = true;
     ThrowNewException("Ljava/lang/OutOfMemoryError;", msg);