meminfo: Add SmapsOrRollupPss

Adds SmapsOrRollup parsing methods to only read Pss of the
process fomr /proc/<pid>/{smaps, smaps_rollup}.

Bug: 111694435
Test: libmeminfo_test 1 --gtest_filter=TestProcMemInfo.*

Change-Id: I31b982ae5ff2bb5b165ea33f6c57755ee34cbbc7
Merged-In: I31b982ae5ff2bb5b165ea33f6c57755ee34cbbc7
Signed-off-by: Sandeep Patil <sspatil@google.com>
diff --git a/libmeminfo/include/meminfo/procmeminfo.h b/libmeminfo/include/meminfo/procmeminfo.h
index c5f8c3c..4cce133 100644
--- a/libmeminfo/include/meminfo/procmeminfo.h
+++ b/libmeminfo/include/meminfo/procmeminfo.h
@@ -66,6 +66,11 @@
     // All other fields of MemUsage are zeroed.
     bool SmapsOrRollup(bool use_rollup, MemUsage* stats) const;
 
+    // Used to parse either of /proc/<pid>/{smaps, smaps_rollup} and record the process's
+    // Pss. The 'use_rollup' parameter decides which file is to be tried.
+    // Returns 'true' on success and the value of Pss in the out parameter.
+    bool SmapsOrRollupPss(bool use_rollup, uint64_t* pss) const;
+
     const std::vector<uint16_t>& SwapOffsets();
 
     ~ProcMemInfo() = default;
@@ -94,5 +99,10 @@
 // or /proc/<pid>/smaps_rollup
 bool SmapsOrRollupFromFile(const std::string& path, MemUsage* stats);
 
+// Same as ProcMemInfo::SmapsOrRollupPss but reads the statistics directly
+// from a file and returns total Pss in kB. The file MUST be in the same format
+// as /proc/<pid>/smaps or /proc/<pid>/smaps_rollup
+bool SmapsOrRollupPssFromFile(const std::string& path, uint64_t* pss);
+
 }  // namespace meminfo
 }  // namespace android
diff --git a/libmeminfo/libmeminfo_test.cpp b/libmeminfo/libmeminfo_test.cpp
index 2529bd7..796a7d0 100644
--- a/libmeminfo/libmeminfo_test.cpp
+++ b/libmeminfo/libmeminfo_test.cpp
@@ -365,6 +365,50 @@
     EXPECT_EQ(stats.swap_pss, 70);
 }
 
+TEST(TestProcMemInfo, SmapsOrRollupPssRollupTest) {
+    // This is a made up smaps for the test
+    std::string smaps =
+            R"smaps(12c00000-13440000 rw-p 00000000 00:00 0                                  [anon:dalvik-main space (region space)]
+Name:           [anon:dalvik-main space (region space)]
+Size:               8448 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Rss:                2652 kB
+Pss:                2652 kB
+Shared_Clean:        840 kB
+Shared_Dirty:         40 kB
+Private_Clean:        84 kB
+Private_Dirty:      2652 kB
+Referenced:         2652 kB
+Anonymous:          2652 kB
+AnonHugePages:         0 kB
+ShmemPmdMapped:        0 kB
+Shared_Hugetlb:        0 kB
+Private_Hugetlb:       0 kB
+Swap:                102 kB
+SwapPss:              70 kB
+Locked:             2652 kB
+VmFlags: rd wr mr mw me ac 
+)smaps";
+
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    ASSERT_TRUE(::android::base::WriteStringToFd(smaps, tf.fd));
+
+    uint64_t pss;
+    ASSERT_EQ(SmapsOrRollupPssFromFile(tf.path, &pss), true);
+    EXPECT_EQ(pss, 2652);
+}
+
+TEST(TestProcMemInfo, SmapsOrRollupPssSmapsTest) {
+    std::string exec_dir = ::android::base::GetExecutableDirectory();
+    std::string path = ::android::base::StringPrintf("%s/testdata1/smaps_short", exec_dir.c_str());
+
+    uint64_t pss;
+    ASSERT_EQ(SmapsOrRollupPssFromFile(path, &pss), true);
+    EXPECT_EQ(pss, 19119);
+}
+
 TEST(TestProcMemInfo, ForEachVmaFromFileTest) {
     std::string exec_dir = ::android::base::GetExecutableDirectory();
     std::string path = ::android::base::StringPrintf("%s/testdata1/smaps_short", exec_dir.c_str());
diff --git a/libmeminfo/procmeminfo.cpp b/libmeminfo/procmeminfo.cpp
index 9345bda..f72d469 100644
--- a/libmeminfo/procmeminfo.cpp
+++ b/libmeminfo/procmeminfo.cpp
@@ -178,6 +178,12 @@
     return SmapsOrRollupFromFile(path, stats);
 };
 
+bool ProcMemInfo::SmapsOrRollupPss(bool use_rollup, uint64_t* pss) const {
+    std::string path = ::android::base::StringPrintf("/proc/%d/%s", pid_,
+                                                     use_rollup ? "smaps_rollup" : "smaps");
+    return SmapsOrRollupPssFromFile(path, pss);
+}
+
 const std::vector<uint16_t>& ProcMemInfo::SwapOffsets() {
     if (get_wss_) {
         LOG(WARNING) << "Trying to read process swap offsets for " << pid_
@@ -412,5 +418,22 @@
     return true;
 }
 
+bool SmapsOrRollupPssFromFile(const std::string& path, uint64_t* pss) {
+    auto fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
+    if (fp == nullptr) {
+        return false;
+    }
+    *pss = 0;
+    char line[1024];
+    while (fgets(line, sizeof(line), fp.get()) != nullptr) {
+        uint64_t v;
+        if (sscanf(line, "Pss: %" SCNu64 " kB", &v) == 1) {
+            *pss += v;
+        }
+    }
+
+    return true;
+}
+
 }  // namespace meminfo
 }  // namespace android