Split ProcessRecord into separate cpp/h files

This change moves the ProcessRecord declaration/definition into
separate processrecord.h/processrecord.cpp files in order to be able to
refer to ProcessRecords in the function signatures at smapinfo.h.

This change also removes the unique_ptr from procmem_ because it is not
needed, and makes ProcessRecord a class instead of a struct.

Test: Checked that showmap, librank, and procrank still work as
      expected.
Bug: 229147699
Change-Id: I501f89bb0daafd18d48e59b779fc69a18ca2eca5
diff --git a/libsmapinfo/Android.bp b/libsmapinfo/Android.bp
index e97b2ba..e421014 100644
--- a/libsmapinfo/Android.bp
+++ b/libsmapinfo/Android.bp
@@ -36,7 +36,8 @@
     host_supported: true,
     defaults: ["smapinfo_defaults"],
     export_include_dirs: ["include"],
-    srcs: ["smapinfo.cpp"],
+    srcs: ["processrecord.cpp",
+           "smapinfo.cpp"],
     target: {
         darwin: {
             enabled: false,
diff --git a/libsmapinfo/include/processrecord.h b/libsmapinfo/include/processrecord.h
new file mode 100644
index 0000000..e40cd43
--- /dev/null
+++ b/libsmapinfo/include/processrecord.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#pragma once
+
+#include <sys/types.h>
+
+#include <cstdint>
+#include <functional>
+#include <ostream>
+#include <string>
+#include <vector>
+
+#include <meminfo/meminfo.h>
+#include <meminfo/procmeminfo.h>
+
+namespace android {
+namespace smapinfo {
+
+class ProcessRecord final {
+  public:
+    ProcessRecord(pid_t pid, bool get_wss, uint64_t pgflags, uint64_t pgflags_mask,
+                  bool get_cmdline, bool get_oomadj, std::ostream& err);
+
+    bool valid() const;
+    void CalculateSwap(const std::vector<uint16_t>& swap_offset_array,
+                       float zram_compression_ratio);
+
+    // Getters
+    pid_t pid() const { return pid_; }
+    const std::string& cmdline() const { return cmdline_; }
+    int32_t oomadj() const { return oomadj_; }
+    uint64_t proportional_swap() const { return proportional_swap_; }
+    uint64_t unique_swap() const { return unique_swap_; }
+    uint64_t zswap() const { return zswap_; }
+
+    // Wrappers to ProcMemInfo
+    const std::vector<uint64_t>& SwapOffsets() const { return swap_offsets_; }
+    // show_wss may be used to return differentiated output in the future.
+    const ::android::meminfo::MemUsage& Usage([[maybe_unused]] bool show_wss) const {
+        return usage_or_wss_;
+    }
+    const std::vector<::android::meminfo::Vma>& Smaps() { return procmem_.Smaps(); }
+    bool ForEachExistingVma(const ::android::meminfo::VmaCallback& callback) {
+        return procmem_.ForEachExistingVma(callback);
+    }
+
+  private:
+    ::android::meminfo::ProcMemInfo procmem_;
+    pid_t pid_;
+    std::string cmdline_;
+    int32_t oomadj_;
+    uint64_t proportional_swap_;
+    uint64_t unique_swap_;
+    uint64_t zswap_;
+    ::android::meminfo::MemUsage usage_or_wss_;
+    std::vector<uint64_t> swap_offsets_;
+};
+
+}  // namespace smapinfo
+}  // namespace android
diff --git a/libsmapinfo/processrecord.cpp b/libsmapinfo/processrecord.cpp
new file mode 100644
index 0000000..bf6d182
--- /dev/null
+++ b/libsmapinfo/processrecord.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#include <inttypes.h>
+#include <linux/oom.h>
+#include <stdlib.h>
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/parseint.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <meminfo/procmeminfo.h>
+
+#include <processrecord.h>
+
+namespace android {
+namespace smapinfo {
+
+using ::android::base::StringPrintf;
+using ::android::meminfo::MemUsage;
+using ::android::meminfo::ProcMemInfo;
+using ::android::meminfo::Vma;
+using ::android::meminfo::VmaCallback;
+
+ProcessRecord::ProcessRecord(pid_t pid, bool get_wss, uint64_t pgflags, uint64_t pgflags_mask,
+                             bool get_cmdline, bool get_oomadj, std::ostream& err)
+    : procmem_(pid, get_wss, pgflags, pgflags_mask),
+      pid_(-1),
+      oomadj_(OOM_SCORE_ADJ_MAX + 1),
+      proportional_swap_(0),
+      unique_swap_(0),
+      zswap_(0) {
+    // cmdline_ only needs to be populated if this record will be used by procrank/librank.
+    if (get_cmdline) {
+        std::string fname = StringPrintf("/proc/%d/cmdline", pid);
+        if (!::android::base::ReadFileToString(fname, &cmdline_)) {
+            err << "Failed to read cmdline from: " << fname << "\n";
+            cmdline_ = "<unknown>";
+        }
+        // We deliberately don't read the /proc/<pid>/cmdline file directly into 'cmdline_'
+        // because some processes have cmdlines that end with "0x00 0x0A 0x00",
+        // e.g. xtra-daemon, lowi-server.
+        // The .c_str() assignment takes care of trimming the cmdline at the first 0x00. This is
+        // how the original procrank worked (luckily).
+        cmdline_.resize(strlen(cmdline_.c_str()));
+    }
+
+    // oomadj_ only needs to be populated if this record will be used by procrank/librank.
+    if (get_oomadj) {
+        std::string fname = StringPrintf("/proc/%d/oom_score_adj", pid);
+        std::string oom_score;
+        if (!::android::base::ReadFileToString(fname, &oom_score)) {
+            err << "Failed to read oom_score_adj file: " << fname << "\n";
+            return;
+        }
+        if (!::android::base::ParseInt(::android::base::Trim(oom_score), &oomadj_)) {
+            err << "Failed to parse oomadj from: " << fname << "\n";
+            return;
+        }
+    }
+
+    // We want to use Smaps() to populate procmem_'s maps before calling Wss() or Usage(), as
+    // these will fall back on the slower ReadMaps().
+    procmem_.Smaps("", true);
+    usage_or_wss_ = get_wss ? procmem_.Wss() : procmem_.Usage();
+    swap_offsets_ = procmem_.SwapOffsets();
+    pid_ = pid;
+}
+
+bool ProcessRecord::valid() const {
+    return pid_ != -1;
+}
+
+void ProcessRecord::CalculateSwap(const std::vector<uint16_t>& swap_offset_array,
+                                  float zram_compression_ratio) {
+    for (auto& off : swap_offsets_) {
+        proportional_swap_ += getpagesize() / swap_offset_array[off];
+        unique_swap_ += swap_offset_array[off] == 1 ? getpagesize() : 0;
+        zswap_ = proportional_swap_ * zram_compression_ratio;
+    }
+    // This is divided by 1024 to convert to KB.
+    proportional_swap_ /= 1024;
+    unique_swap_ /= 1024;
+    zswap_ /= 1024;
+}
+
+}  // namespace smapinfo
+}  // namespace android
diff --git a/libsmapinfo/smapinfo.cpp b/libsmapinfo/smapinfo.cpp
index 03288a2..19bcb55 100644
--- a/libsmapinfo/smapinfo.cpp
+++ b/libsmapinfo/smapinfo.cpp
@@ -30,9 +30,9 @@
 #include <android-base/parseint.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
-#include <meminfo/procmeminfo.h>
 #include <meminfo/sysmeminfo.h>
 
+#include <processrecord.h>
 #include <smapinfo.h>
 
 namespace android {
@@ -43,108 +43,7 @@
 using ::android::meminfo::EscapeJsonString;
 using ::android::meminfo::Format;
 using ::android::meminfo::MemUsage;
-using ::android::meminfo::ProcMemInfo;
 using ::android::meminfo::Vma;
-using ::android::meminfo::VmaCallback;
-
-struct ProcessRecord {
-  public:
-    ProcessRecord(pid_t pid, bool get_wss, uint64_t pgflags, uint64_t pgflags_mask,
-                  bool get_cmdline, bool get_oomadj, std::ostream& err)
-        : pid_(-1),
-          oomadj_(OOM_SCORE_ADJ_MAX + 1),
-          proportional_swap_(0),
-          unique_swap_(0),
-          zswap_(0) {
-        procmem_ = std::make_unique<ProcMemInfo>(pid, get_wss, pgflags, pgflags_mask);
-        if (procmem_ == nullptr) {
-            err << "Failed to create ProcMemInfo for: " << pid << "\n";
-            return;
-        }
-
-        // cmdline_ only needs to be populated if this record will be used by procrank/librank.
-        if (get_cmdline) {
-            std::string fname = StringPrintf("/proc/%d/cmdline", pid);
-            if (!::android::base::ReadFileToString(fname, &cmdline_)) {
-                std::cerr << "Failed to read cmdline from: " << fname << "\n";
-                cmdline_ = "<unknown>";
-            }
-            // We deliberately don't read the /proc/<pid>/cmdline file directly into 'cmdline_'
-            // because some processes have cmdlines that end with "0x00 0x0A 0x00",
-            // e.g. xtra-daemon, lowi-server.
-            // The .c_str() assignment takes care of trimming the cmdline at the first 0x00. This is
-            // how the original procrank worked (luckily).
-            cmdline_.resize(strlen(cmdline_.c_str()));
-        }
-
-        // oomadj_ only needs to be populated if this record will be used by procrank/librank.
-        if (get_oomadj) {
-            std::string fname = StringPrintf("/proc/%d/oom_score_adj", pid);
-            std::string oom_score;
-            if (!::android::base::ReadFileToString(fname, &oom_score)) {
-                std::cerr << "Failed to read oom_score_adj file: " << fname << "\n";
-                return;
-            }
-            if (!::android::base::ParseInt(::android::base::Trim(oom_score), &oomadj_)) {
-                std::cerr << "Failed to parse oomadj from: " << fname << "\n";
-                return;
-            }
-        }
-
-        // We want to use Smaps() to populate procmem_'s maps before calling Wss() or Usage(), as
-        // these will fall back on the slower ReadMaps().
-        procmem_->Smaps("", true);
-        usage_or_wss_ = get_wss ? procmem_->Wss() : procmem_->Usage();
-        swap_offsets_ = procmem_->SwapOffsets();
-        pid_ = pid;
-    }
-
-    bool valid() const { return pid_ != -1; }
-
-    void CalculateSwap(const std::vector<uint16_t>& swap_offset_array,
-                       float zram_compression_ratio) {
-        for (auto& off : swap_offsets_) {
-            proportional_swap_ += getpagesize() / swap_offset_array[off];
-            unique_swap_ += swap_offset_array[off] == 1 ? getpagesize() : 0;
-            zswap_ = proportional_swap_ * zram_compression_ratio;
-        }
-        // This is divided by 1024 to convert to KB.
-        proportional_swap_ /= 1024;
-        unique_swap_ /= 1024;
-        zswap_ /= 1024;
-    }
-
-    // Getters
-    pid_t pid() const { return pid_; }
-    const std::string& cmdline() const { return cmdline_; }
-    int32_t oomadj() const { return oomadj_; }
-    uint64_t proportional_swap() const { return proportional_swap_; }
-    uint64_t unique_swap() const { return unique_swap_; }
-    uint64_t zswap() const { return zswap_; }
-
-    // Wrappers to ProcMemInfo
-    const std::vector<uint64_t>& SwapOffsets() const { return swap_offsets_; }
-    // show_wss may be used to return differentiated output in the future.
-    const MemUsage& Usage([[maybe_unused]] bool show_wss) const { return usage_or_wss_; }
-
-    // This will not result in a second reading of the smaps file because procmem_->Smaps() has
-    // already been called in the constructor.
-    const std::vector<Vma>& Smaps() const { return procmem_->Smaps(); }
-    bool ForEachExistingVma(const VmaCallback& callback) {
-        return procmem_->ForEachExistingVma(callback);
-    }
-
-  private:
-    std::unique_ptr<ProcMemInfo> procmem_;
-    pid_t pid_;
-    std::string cmdline_;
-    int32_t oomadj_;
-    uint64_t proportional_swap_;
-    uint64_t unique_swap_;
-    uint64_t zswap_;
-    MemUsage usage_or_wss_;
-    std::vector<uint64_t> swap_offsets_;
-};
 
 bool get_all_pids(std::set<pid_t>* pids) {
     pids->clear();