Remove static constructors from libmeminfo

This CL changes libmeminfo's API to be less picky about the types of
its inputs and outputs and exposes the list of default memory types as
a constexpr std::array that doesn't need to be constructed as
dlopen time.

Test: tests pass; device boots
Bug: 140456977
Change-Id: Ice45a5400cc77540fb13352bba1adb7737877bcb
diff --git a/libmeminfo/include/meminfo/sysmeminfo.h b/libmeminfo/include/meminfo/sysmeminfo.h
index 8388920..4a5a18b 100644
--- a/libmeminfo/include/meminfo/sysmeminfo.h
+++ b/libmeminfo/include/meminfo/sysmeminfo.h
@@ -18,10 +18,12 @@
 
 #include <sys/types.h>
 
+#include <array>
 #include <functional>
+#include <initializer_list>
 #include <map>
 #include <string>
-#include <vector>
+#include <string_view>
 
 namespace android {
 namespace meminfo {
@@ -29,30 +31,36 @@
 class SysMemInfo final {
     // System or Global memory accounting
   public:
-    static constexpr const char* kMemTotal = "MemTotal:";
-    static constexpr const char* kMemFree = "MemFree:";
-    static constexpr const char* kMemBuffers = "Buffers:";
-    static constexpr const char* kMemCached = "Cached:";
-    static constexpr const char* kMemShmem = "Shmem:";
-    static constexpr const char* kMemSlab = "Slab:";
-    static constexpr const char* kMemSReclaim = "SReclaimable:";
-    static constexpr const char* kMemSUnreclaim = "SUnreclaim:";
-    static constexpr const char* kMemSwapTotal = "SwapTotal:";
-    static constexpr const char* kMemSwapFree = "SwapFree:";
-    static constexpr const char* kMemMapped = "Mapped:";
-    static constexpr const char* kMemVmallocUsed = "VmallocUsed:";
-    static constexpr const char* kMemPageTables = "PageTables:";
-    static constexpr const char* kMemKernelStack = "KernelStack:";
+    static constexpr const char kMemTotal[] = "MemTotal:";
+    static constexpr const char kMemFree[] = "MemFree:";
+    static constexpr const char kMemBuffers[] = "Buffers:";
+    static constexpr const char kMemCached[] = "Cached:";
+    static constexpr const char kMemShmem[] = "Shmem:";
+    static constexpr const char kMemSlab[] = "Slab:";
+    static constexpr const char kMemSReclaim[] = "SReclaimable:";
+    static constexpr const char kMemSUnreclaim[] = "SUnreclaim:";
+    static constexpr const char kMemSwapTotal[] = "SwapTotal:";
+    static constexpr const char kMemSwapFree[] = "SwapFree:";
+    static constexpr const char kMemMapped[] = "Mapped:";
+    static constexpr const char kMemVmallocUsed[] = "VmallocUsed:";
+    static constexpr const char kMemPageTables[] = "PageTables:";
+    static constexpr const char kMemKernelStack[] = "KernelStack:";
 
-    static const std::vector<std::string> kDefaultSysMemInfoTags;
+    static constexpr std::initializer_list<std::string_view> kDefaultSysMemInfoTags = {
+            SysMemInfo::kMemTotal,      SysMemInfo::kMemFree,        SysMemInfo::kMemBuffers,
+            SysMemInfo::kMemCached,     SysMemInfo::kMemShmem,       SysMemInfo::kMemSlab,
+            SysMemInfo::kMemSReclaim,   SysMemInfo::kMemSUnreclaim,  SysMemInfo::kMemSwapTotal,
+            SysMemInfo::kMemSwapFree,   SysMemInfo::kMemMapped,      SysMemInfo::kMemVmallocUsed,
+            SysMemInfo::kMemPageTables, SysMemInfo::kMemKernelStack,
+    };
 
     SysMemInfo() = default;
 
     // Parse /proc/meminfo and read values that are needed
-    bool ReadMemInfo(const std::string& path = "/proc/meminfo");
-    bool ReadMemInfo(const std::vector<std::string>& tags, std::vector<uint64_t>* out,
-                     const std::string& path = "/proc/meminfo");
-    bool ReadMemInfo(std::vector<uint64_t>* out, const std::string& path = "/proc/meminfo");
+    bool ReadMemInfo(const char* path = "/proc/meminfo");
+    bool ReadMemInfo(size_t ntags, const std::string_view* tags, uint64_t* out,
+                     const char* path = "/proc/meminfo");
+    bool ReadMemInfo(std::vector<uint64_t>* out, const char* path = "/proc/meminfo");
 
     // Parse /proc/vmallocinfo and return total physical memory mapped
     // in vmalloc area by the kernel.
@@ -75,19 +83,19 @@
     uint64_t mem_vmalloc_used_kb() { return mem_in_kb_[kMemVmallocUsed]; }
     uint64_t mem_page_tables_kb() { return mem_in_kb_[kMemPageTables]; }
     uint64_t mem_kernel_stack_kb() { return mem_in_kb_[kMemKernelStack]; }
-    uint64_t mem_zram_kb(const std::string& zram_dev = "");
+    uint64_t mem_zram_kb(const char* zram_dev = nullptr);
 
   private:
-    std::map<std::string, uint64_t> mem_in_kb_;
-    bool MemZramDevice(const std::string& zram_dev, uint64_t* mem_zram_dev);
-    bool ReadMemInfo(const std::vector<std::string>& tags, const std::string& path,
-                     std::function<void(const std::string&, uint64_t)> store_val);
+    std::map<std::string_view, uint64_t> mem_in_kb_;
+    bool MemZramDevice(const char* zram_dev, uint64_t* mem_zram_dev);
+    bool ReadMemInfo(const char* path, size_t ntags, const std::string_view* tags,
+                     std::function<void(std::string_view, uint64_t)> store_val);
 };
 
 // Parse /proc/vmallocinfo and return total physical memory mapped
 // in vmalloc area by the kernel. Note that this deliberately ignores binder buffers. They are
 // _always_ mapped in a process and are counted for in each process.
-uint64_t ReadVmallocInfo(const std::string& path = "/proc/vmallocinfo");
+uint64_t ReadVmallocInfo(const char* path = "/proc/vmallocinfo");
 
 }  // namespace meminfo
 }  // namespace android
diff --git a/libmeminfo/libmeminfo_benchmark.cpp b/libmeminfo/libmeminfo_benchmark.cpp
index d88919b..7450c6c 100644
--- a/libmeminfo/libmeminfo_benchmark.cpp
+++ b/libmeminfo/libmeminfo_benchmark.cpp
@@ -218,8 +218,8 @@
     android::base::WriteStringToFd(meminfo, tf.fd);
 
     std::string file = std::string(tf.path);
-    std::vector<uint64_t> mem(MEMINFO_COUNT);
-    const std::vector<std::string> tags = {
+    std::vector<uint64_t> mem;
+    const std::vector<std::string_view> tags = {
             SysMemInfo::kMemTotal,      SysMemInfo::kMemFree,        SysMemInfo::kMemBuffers,
             SysMemInfo::kMemCached,     SysMemInfo::kMemShmem,       SysMemInfo::kMemSlab,
             SysMemInfo::kMemSReclaim,   SysMemInfo::kMemSUnreclaim,  SysMemInfo::kMemSwapTotal,
@@ -229,7 +229,8 @@
 
     SysMemInfo smi;
     for (auto _ : state) {
-        smi.ReadMemInfo(tags, &mem, file);
+        mem.resize(tags.size());
+        smi.ReadMemInfo(tags.size(), tags.data(), mem.data(), file.c_str());
     }
 }
 BENCHMARK(BM_ReadMemInfo_new);
@@ -276,7 +277,7 @@
     std::string zram_mmstat_dir = exec_dir + "/testdata1/";
     SysMemInfo smi;
     for (auto _ : state) {
-        uint64_t zram_total __attribute__((unused)) = smi.mem_zram_kb(zram_mmstat_dir);
+        uint64_t zram_total __attribute__((unused)) = smi.mem_zram_kb(zram_mmstat_dir.c_str());
     }
 }
 BENCHMARK(BM_ZramTotal_new);
@@ -390,14 +391,16 @@
     android::base::WriteStringToFd(meminfo, tf.fd);
 
     std::string file = std::string(tf.path);
-    std::vector<uint64_t> mem(MEMINFO_COUNT);
-    std::vector<std::string> tags(SysMemInfo::kDefaultSysMemInfoTags);
+    std::vector<uint64_t> mem;
+    std::vector<std::string_view> tags(SysMemInfo::kDefaultSysMemInfoTags.begin(),
+                                       SysMemInfo::kDefaultSysMemInfoTags.end());
     auto it = tags.begin();
     tags.insert(it + MEMINFO_ZRAM_TOTAL, "Zram:");
     SysMemInfo smi;
 
     for (auto _ : state) {
-        smi.ReadMemInfo(tags, &mem, file);
+        mem.resize(tags.size());
+        smi.ReadMemInfo(tags.size(), tags.data(), mem.data(), file.c_str());
         CHECK_EQ(mem[MEMINFO_KERNEL_STACK], 4880u);
     }
 }
@@ -455,7 +458,7 @@
     std::string vmallocinfo =
             ::android::base::StringPrintf("%s/testdata1/vmallocinfo", exec_dir.c_str());
     for (auto _ : state) {
-        CHECK_EQ(::android::meminfo::ReadVmallocInfo(vmallocinfo), 29884416);
+        CHECK_EQ(::android::meminfo::ReadVmallocInfo(vmallocinfo.c_str()), 29884416);
     }
 }
 BENCHMARK(BM_VmallocInfo_new);
diff --git a/libmeminfo/libmeminfo_test.cpp b/libmeminfo/libmeminfo_test.cpp
index 4c2be91..00e139f 100644
--- a/libmeminfo/libmeminfo_test.cpp
+++ b/libmeminfo/libmeminfo_test.cpp
@@ -585,10 +585,10 @@
 
     SysMemInfo mi;
     std::string zram_mmstat_dir = exec_dir + "/testdata1/";
-    EXPECT_EQ(mi.mem_zram_kb(zram_mmstat_dir), 30504);
+    EXPECT_EQ(mi.mem_zram_kb(zram_mmstat_dir.c_str()), 30504);
 
     std::string zram_memused_dir = exec_dir + "/testdata2/";
-    EXPECT_EQ(mi.mem_zram_kb(zram_memused_dir), 30504);
+    EXPECT_EQ(mi.mem_zram_kb(zram_memused_dir.c_str()), 30504);
 }
 
 enum {
@@ -660,15 +660,16 @@
     ASSERT_TRUE(tf.fd != -1);
     ASSERT_TRUE(::android::base::WriteStringToFd(meminfo, tf.fd));
     std::string file = std::string(tf.path);
-    std::vector<uint64_t> mem(MEMINFO_COUNT);
-    std::vector<std::string> tags(SysMemInfo::kDefaultSysMemInfoTags);
+    std::vector<uint64_t> mem;
+    std::vector<std::string_view> tags(SysMemInfo::kDefaultSysMemInfoTags.begin(),
+                                       SysMemInfo::kDefaultSysMemInfoTags.end());
     auto it = tags.begin();
     tags.insert(it + MEMINFO_ZRAM_TOTAL, "Zram:");
     SysMemInfo mi;
 
     // Read system memory info
-    EXPECT_TRUE(mi.ReadMemInfo(tags, &mem, file));
-
+    mem.resize(tags.size());
+    EXPECT_TRUE(mi.ReadMemInfo(tags.size(), tags.data(), mem.data(), file.c_str()));
     EXPECT_EQ(mem[MEMINFO_TOTAL], 3019740);
     EXPECT_EQ(mem[MEMINFO_FREE], 1809728);
     EXPECT_EQ(mem[MEMINFO_BUFFERS], 54736);
@@ -697,7 +698,7 @@
     ASSERT_TRUE(::android::base::WriteStringToFd(vmallocinfo, tf.fd));
     std::string file = std::string(tf.path);
 
-    EXPECT_EQ(ReadVmallocInfo(file), 0);
+    EXPECT_EQ(ReadVmallocInfo(file.c_str()), 0);
 }
 
 TEST(SysMemInfo, TestVmallocInfoKernel) {
@@ -709,7 +710,7 @@
     ASSERT_TRUE(::android::base::WriteStringToFd(vmallocinfo, tf.fd));
     std::string file = std::string(tf.path);
 
-    EXPECT_EQ(ReadVmallocInfo(file), getpagesize());
+    EXPECT_EQ(ReadVmallocInfo(file.c_str()), getpagesize());
 }
 
 TEST(SysMemInfo, TestVmallocInfoModule) {
@@ -721,7 +722,7 @@
     ASSERT_TRUE(::android::base::WriteStringToFd(vmallocinfo, tf.fd));
     std::string file = std::string(tf.path);
 
-    EXPECT_EQ(ReadVmallocInfo(file), 6 * getpagesize());
+    EXPECT_EQ(ReadVmallocInfo(file.c_str()), 6 * getpagesize());
 }
 
 TEST(SysMemInfo, TestVmallocInfoAll) {
@@ -738,7 +739,7 @@
     ASSERT_TRUE(::android::base::WriteStringToFd(vmallocinfo, tf.fd));
     std::string file = std::string(tf.path);
 
-    EXPECT_EQ(ReadVmallocInfo(file), 7 * getpagesize());
+    EXPECT_EQ(ReadVmallocInfo(file.c_str()), 7 * getpagesize());
 }
 
 int main(int argc, char** argv) {
diff --git a/libmeminfo/sysmeminfo.cpp b/libmeminfo/sysmeminfo.cpp
index 5cfa6c3..ef68ac4 100644
--- a/libmeminfo/sysmeminfo.cpp
+++ b/libmeminfo/sysmeminfo.cpp
@@ -45,37 +45,36 @@
 namespace android {
 namespace meminfo {
 
-const std::vector<std::string> SysMemInfo::kDefaultSysMemInfoTags = {
-        SysMemInfo::kMemTotal,      SysMemInfo::kMemFree,        SysMemInfo::kMemBuffers,
-        SysMemInfo::kMemCached,     SysMemInfo::kMemShmem,       SysMemInfo::kMemSlab,
-        SysMemInfo::kMemSReclaim,   SysMemInfo::kMemSUnreclaim,  SysMemInfo::kMemSwapTotal,
-        SysMemInfo::kMemSwapFree,   SysMemInfo::kMemMapped,      SysMemInfo::kMemVmallocUsed,
-        SysMemInfo::kMemPageTables, SysMemInfo::kMemKernelStack,
-};
-
-bool SysMemInfo::ReadMemInfo(const std::string& path) {
-    return ReadMemInfo(SysMemInfo::kDefaultSysMemInfoTags, path,
-                       [&](const std::string& tag, uint64_t val) { mem_in_kb_[tag] = val; });
+bool SysMemInfo::ReadMemInfo(const char* path) {
+    return ReadMemInfo(path, SysMemInfo::kDefaultSysMemInfoTags.size(),
+                       &*SysMemInfo::kDefaultSysMemInfoTags.begin(),
+                       [&](std::string_view tag, uint64_t val) {
+                           // Safe to store the string_view in the map
+                           // because the tags from
+                           // kDefaultSysMemInfoTags are all
+                           // statically-allocated.
+                           mem_in_kb_[tag] = val;
+                       });
 }
 
-bool SysMemInfo::ReadMemInfo(std::vector<uint64_t>* out, const std::string& path) {
-    return ReadMemInfo(SysMemInfo::kDefaultSysMemInfoTags, out, path);
-}
-
-bool SysMemInfo::ReadMemInfo(const std::vector<std::string>& tags, std::vector<uint64_t>* out,
-                             const std::string& path) {
+bool SysMemInfo::ReadMemInfo(std::vector<uint64_t>* out, const char* path) {
     out->clear();
-    out->resize(tags.size());
+    out->resize(SysMemInfo::kDefaultSysMemInfoTags.size());
+    return ReadMemInfo(SysMemInfo::kDefaultSysMemInfoTags.size(),
+                       &*SysMemInfo::kDefaultSysMemInfoTags.begin(), out->data(), path);
+}
 
-    return ReadMemInfo(tags, path, [&]([[maybe_unused]] const std::string& tag, uint64_t val) {
-        auto it = std::find(tags.begin(), tags.end(), tag);
-        if (it == tags.end()) {
+bool SysMemInfo::ReadMemInfo(size_t ntags, const std::string_view* tags, uint64_t* out,
+                             const char* path) {
+    return ReadMemInfo(path, ntags, tags, [&]([[maybe_unused]] std::string_view tag, uint64_t val) {
+        auto it = std::find(tags, tags + ntags, tag);
+        if (it == tags + ntags) {
             LOG(ERROR) << "Tried to store invalid tag: " << tag;
             return;
         }
-        auto index = std::distance(tags.begin(), it);
+        auto index = std::distance(tags, it);
         // store the values in the same order as the tags
-        out->at(index) = val;
+        out[index] = val;
     });
 }
 
@@ -83,46 +82,10 @@
     return ::android::meminfo::ReadVmallocInfo();
 }
 
-// TODO: Delete this function if it can't match up with the c-like implementation below.
-// Currently, this added about 50 % extra overhead on hikey.
-#if 0
-bool SysMemInfo::ReadMemInfo(const std::vector<std::string>& tags, const std::string& path) {
-    std::string buffer;
-    if (!::android::base::ReadFileToString(path, &buffer)) {
-        PLOG(ERROR) << "Failed to read : " << path;
-        return false;
-    }
-
-    uint32_t total_found = 0;
-    for (auto s = buffer.begin(); s < buffer.end() && total_found < tags.size();) {
-        for (auto& tag : tags) {
-            if (tag == std::string(s, s + tag.size())) {
-                s += tag.size();
-                while (isspace(*s)) s++;
-                auto num_start = s;
-                while (std::isdigit(*s)) s++;
-
-                std::string number(num_start, num_start + (s - num_start));
-                if (!::android::base::ParseUint(number, &mem_in_kb_[tag])) {
-                    LOG(ERROR) << "Failed to parse uint";
-                    return false;
-                }
-                total_found++;
-                break;
-            }
-        }
-        while (s < buffer.end() && *s != '\n') s++;
-        if (s < buffer.end()) s++;
-    }
-
-    return true;
-}
-
-#else
-bool SysMemInfo::ReadMemInfo(const std::vector<std::string>& tags, const std::string& path,
-                             std::function<void(const std::string&, uint64_t)> store_val) {
+bool SysMemInfo::ReadMemInfo(const char* path, size_t ntags, const std::string_view* tags,
+                             std::function<void(std::string_view, uint64_t)> store_val) {
     char buffer[4096];
-    int fd = open(path.c_str(), O_RDONLY | O_CLOEXEC);
+    int fd = open(path, O_RDONLY | O_CLOEXEC);
     if (fd < 0) {
         PLOG(ERROR) << "Failed to open file :" << path;
         return false;
@@ -139,8 +102,9 @@
     uint32_t found = 0;
     uint32_t lineno = 0;
     bool zram_tag_found = false;
-    while (*p && found < tags.size()) {
-        for (auto& tag : tags) {
+    while (*p && found < ntags) {
+        for (size_t tagno = 0; tagno < ntags; ++tagno) {
+            const std::string_view& tag = tags[tagno];
             // Special case for "Zram:" tag that android_os_Debug and friends look
             // up along with the rest of the numbers from /proc/meminfo
             if (!zram_tag_found && tag == "Zram:") {
@@ -150,7 +114,7 @@
                 continue;
             }
 
-            if (strncmp(p, tag.c_str(), tag.size()) == 0) {
+            if (strncmp(p, tag.data(), tag.size()) == 0) {
                 p += tag.size();
                 while (*p == ' ') p++;
                 char* endptr = nullptr;
@@ -175,12 +139,11 @@
 
     return true;
 }
-#endif
 
-uint64_t SysMemInfo::mem_zram_kb(const std::string& zram_dev) {
+uint64_t SysMemInfo::mem_zram_kb(const char* zram_dev_cstr) {
     uint64_t mem_zram_total = 0;
-    if (!zram_dev.empty()) {
-        if (!MemZramDevice(zram_dev, &mem_zram_total)) {
+    if (zram_dev_cstr) {
+        if (!MemZramDevice(zram_dev_cstr, &mem_zram_total)) {
             return 0;
         }
         return mem_zram_total / 1024;
@@ -188,15 +151,15 @@
 
     constexpr uint32_t kMaxZramDevices = 256;
     for (uint32_t i = 0; i < kMaxZramDevices; i++) {
-        std::string zram_dev = ::android::base::StringPrintf("/sys/block/zram%u/", i);
-        if (access(zram_dev.c_str(), F_OK)) {
+        std::string zram_dev_abspath = ::android::base::StringPrintf("/sys/block/zram%u/", i);
+        if (access(zram_dev_abspath.c_str(), F_OK)) {
             // We assume zram devices appear in range 0-255 and appear always in sequence
             // under /sys/block. So, stop looking for them once we find one is missing.
             break;
         }
 
         uint64_t mem_zram_dev;
-        if (!MemZramDevice(zram_dev, &mem_zram_dev)) {
+        if (!MemZramDevice(zram_dev_abspath.c_str(), &mem_zram_dev)) {
             return 0;
         }
 
@@ -206,8 +169,8 @@
     return mem_zram_total / 1024;
 }
 
-bool SysMemInfo::MemZramDevice(const std::string& zram_dev, uint64_t* mem_zram_dev) {
-    std::string mmstat = ::android::base::StringPrintf("%s/%s", zram_dev.c_str(), "mm_stat");
+bool SysMemInfo::MemZramDevice(const char* zram_dev, uint64_t* mem_zram_dev) {
+    std::string mmstat = ::android::base::StringPrintf("%s/%s", zram_dev, "mm_stat");
     auto mmstat_fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(mmstat.c_str(), "re"), fclose};
     if (mmstat_fp != nullptr) {
         // only if we do have mmstat, use it. Otherwise, fall through to trying out the old
@@ -220,7 +183,8 @@
     }
 
     std::string content;
-    if (::android::base::ReadFileToString(zram_dev + "mem_used_total", &content)) {
+    if (::android::base::ReadFileToString(
+                ::android::base::StringPrintf("%s/mem_used_total", zram_dev), &content)) {
         *mem_zram_dev = strtoull(content.c_str(), NULL, 10);
         if (*mem_zram_dev == ULLONG_MAX) {
             PLOG(ERROR) << "Malformed mem_used_total file for zram dev: " << zram_dev
@@ -236,9 +200,9 @@
 }
 
 // Public methods
-uint64_t ReadVmallocInfo(const std::string& path) {
+uint64_t ReadVmallocInfo(const char* path) {
     uint64_t vmalloc_total = 0;
-    auto fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
+    auto fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path, "re"), fclose};
     if (fp == nullptr) {
         return vmalloc_total;
     }