Snap for 8730993 from 91c67215e53b8a6ce9dcf4575df253c4070b07da to mainline-tzdata3-release
Change-Id: If46464c85b60f24d08e6d5e1cb0ddfd3f044ba57
diff --git a/Android.bp b/Android.bp
index d16b05d..7306d44 100644
--- a/Android.bp
+++ b/Android.bp
@@ -34,6 +34,21 @@
"libdmabufinfo",
],
target: {
+ android: {
+ static_libs: [
+ "libbpf_android",
+ ],
+ },
+ apex: {
+ exclude_static_libs: [
+ "libbpf_android",
+ ],
+ },
+ vendor: {
+ exclude_static_libs: [
+ "libbpf_android",
+ ],
+ },
darwin: {
enabled: false,
},
@@ -52,7 +67,6 @@
"libdmabufinfo/include",
],
export_shared_lib_headers: ["libbase"],
- header_libs: ["bpf_headers"],
srcs: [
"pageacct.cpp",
"procmeminfo.cpp",
diff --git a/OWNERS b/OWNERS
index 5a7a0bd..b15bb48 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,2 +1 @@
-# Bug component: 391836
surenb@google.com
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 8dae108..32750b0 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -3,10 +3,5 @@
{
"name": "libmeminfo_test"
}
- ],
- "hwasan-postsubmit": [
- {
- "name": "libmeminfo_test"
- }
]
}
diff --git a/include/meminfo/sysmeminfo.h b/include/meminfo/sysmeminfo.h
index a17f8ef..175a0df 100644
--- a/include/meminfo/sysmeminfo.h
+++ b/include/meminfo/sysmeminfo.h
@@ -24,7 +24,6 @@
#include <map>
#include <string>
#include <string_view>
-#include <unordered_map>
namespace android {
namespace meminfo {
@@ -122,12 +121,6 @@
bool ReadDmabufHeapPoolsSizeKb(uint64_t* size,
const std::string& path = "/sys/kernel/dma_heap/total_pools_kb");
-// Read per-process GPU memory usage. Returns a map of pid -> GPU Mem in kilobytes.
-bool ReadPerProcessGpuMem(std::unordered_map<uint32_t, uint64_t>* out);
-
-// Read GPU usage of the specified process in kb.
-bool ReadProcessGpuUsageKb(uint32_t pid, uint32_t gpu_id, uint64_t* size);
-
// Read GPU total usage size in kb
bool ReadGpuTotalUsageKb(uint64_t* size);
diff --git a/libdmabufinfo/dmabufinfo.cpp b/libdmabufinfo/dmabufinfo.cpp
index cb639c1..422fc6e 100644
--- a/libdmabufinfo/dmabufinfo.cpp
+++ b/libdmabufinfo/dmabufinfo.cpp
@@ -302,36 +302,5 @@
return true;
}
-bool ReadDmaBufs(std::vector<DmaBuffer>* bufs) {
- bufs->clear();
-
- std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir("/proc"), closedir);
- if (!dir) {
- LOG(ERROR) << "Failed to open /proc directory";
- bufs->clear();
- return false;
- }
-
- struct dirent* dent;
- while ((dent = readdir(dir.get()))) {
- if (dent->d_type != DT_DIR) continue;
-
- int pid = atoi(dent->d_name);
- if (pid == 0) {
- continue;
- }
-
- if (!ReadDmaBufFdRefs(pid, bufs)) {
- LOG(ERROR) << "Failed to read dmabuf fd references for pid " << pid;
- }
-
- if (!ReadDmaBufMapRefs(pid, bufs)) {
- LOG(ERROR) << "Failed to read dmabuf map references for pid " << pid;
- }
- }
-
- return true;
-}
-
} // namespace dmabufinfo
} // namespace android
diff --git a/libdmabufinfo/include/dmabufinfo/dmabufinfo.h b/libdmabufinfo/include/dmabufinfo/dmabufinfo.h
index bb4aff1..93736df 100644
--- a/libdmabufinfo/include/dmabufinfo/dmabufinfo.h
+++ b/libdmabufinfo/include/dmabufinfo/dmabufinfo.h
@@ -127,10 +127,5 @@
bool ReadDmaBufPss(int pid, uint64_t* pss, const std::string& procfs_path = "/proc",
const std::string& dmabuf_sysfs_path = "/sys/kernel/dmabuf/buffers");
-// Writes DmaBuffer info into an existing vector (which will be cleared first.)
-// Will include all DmaBuffers, whether thay are retained or mapped.
-// Returns true on success, otherwise false.
-bool ReadDmaBufs(std::vector<DmaBuffer>* bufs);
-
} // namespace dmabufinfo
} // namespace android
diff --git a/libdmabufinfo/tools/dmabuf_dump.cpp b/libdmabufinfo/tools/dmabuf_dump.cpp
index 65ebd08..57204f6 100644
--- a/libdmabufinfo/tools/dmabuf_dump.cpp
+++ b/libdmabufinfo/tools/dmabuf_dump.cpp
@@ -179,6 +179,45 @@
total_size / 1024, kernel_rss / 1024, total_rss / 1024, total_pss / 1024);
}
+static bool ReadDmaBufs(std::vector<DmaBuffer>* bufs) {
+ bufs->clear();
+
+ if (!ReadDmaBufInfo(bufs)) {
+ printf("debugfs entry for dmabuf not available, using /proc/<pid>/fdinfo instead\n");
+ }
+
+ std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir("/proc"), closedir);
+ if (!dir) {
+ fprintf(stderr, "Failed to open /proc directory\n");
+ bufs->clear();
+ return false;
+ }
+
+ struct dirent* dent;
+ while ((dent = readdir(dir.get()))) {
+ if (dent->d_type != DT_DIR) continue;
+
+ int pid = atoi(dent->d_name);
+ if (pid == 0) {
+ continue;
+ }
+
+ if (!ReadDmaBufFdRefs(pid, bufs)) {
+ fprintf(stderr, "Failed to read dmabuf fd references for pid %d\n", pid);
+ bufs->clear();
+ return false;
+ }
+
+ if (!ReadDmaBufMapRefs(pid, bufs)) {
+ fprintf(stderr, "Failed to read dmabuf map references for pid %d\n", pid);
+ bufs->clear();
+ return false;
+ }
+ }
+
+ return true;
+}
+
static void DumpDmabufSysfsStats() {
android::dmabufinfo::DmabufSysfsStats stats;
@@ -261,10 +300,7 @@
exit(EXIT_FAILURE);
}
} else {
- if (!ReadDmaBufs(&bufs)) {
- fprintf(stderr, "Failed to ReadDmaBufs, check logcat for info\n");
- exit(EXIT_FAILURE);
- }
+ if (!ReadDmaBufs(&bufs)) exit(EXIT_FAILURE);
}
// Show the old dmabuf table, inode x process
diff --git a/libmeminfo_test.cpp b/libmeminfo_test.cpp
index 20159bf..c41e4ff 100644
--- a/libmeminfo_test.cpp
+++ b/libmeminfo_test.cpp
@@ -967,7 +967,7 @@
TEST(SysMemInfo, TestReadGpuTotalUsageKb) {
uint64_t size;
- if (android::base::GetIntProperty("ro.vendor.api_level", 0) < __ANDROID_API_S__) {
+ if (android::base::GetIntProperty("ro.product.first_api_level", 0) < __ANDROID_API_S__) {
GTEST_SKIP();
}
diff --git a/procmeminfo.cpp b/procmeminfo.cpp
index 13a17da..af64f86 100644
--- a/procmeminfo.cpp
+++ b/procmeminfo.cpp
@@ -68,58 +68,55 @@
// Returns true if the line was valid smaps stats line false otherwise.
static bool parse_smaps_field(const char* line, MemUsage* stats) {
- const char *end = line;
-
- // https://lore.kernel.org/patchwork/patch/1088579/ introduced tabs. Handle this case as well.
- while (*end && !isspace(*end)) end++;
- if (*end && end > line && *(end - 1) == ':') {
- const char* c = end;
- while (isspace(*c)) c++;
- switch (line[0]) {
+ char field[64];
+ int len;
+ if (sscanf(line, "%63s %n", field, &len) == 1 && *field && field[strlen(field) - 1] == ':') {
+ const char* c = line + len;
+ switch (field[0]) {
case 'P':
- if (strncmp(line, "Pss:", 4) == 0) {
+ if (strncmp(field, "Pss:", 4) == 0) {
stats->pss = strtoull(c, nullptr, 10);
- } else if (strncmp(line, "Private_Clean:", 14) == 0) {
+ } else if (strncmp(field, "Private_Clean:", 14) == 0) {
uint64_t prcl = strtoull(c, nullptr, 10);
stats->private_clean = prcl;
stats->uss += prcl;
- } else if (strncmp(line, "Private_Dirty:", 14) == 0) {
+ } else if (strncmp(field, "Private_Dirty:", 14) == 0) {
uint64_t prdi = strtoull(c, nullptr, 10);
stats->private_dirty = prdi;
stats->uss += prdi;
- } else if (strncmp(line, "Private_Hugetlb:", 16) == 0) {
+ } else if (strncmp(field, "Private_Hugetlb:", 16) == 0) {
stats->private_hugetlb = strtoull(c, nullptr, 10);
}
break;
case 'S':
- if (strncmp(line, "Size:", 5) == 0) {
+ if (strncmp(field, "Size:", 5) == 0) {
stats->vss = strtoull(c, nullptr, 10);
- } else if (strncmp(line, "Shared_Clean:", 13) == 0) {
+ } else if (strncmp(field, "Shared_Clean:", 13) == 0) {
stats->shared_clean = strtoull(c, nullptr, 10);
- } else if (strncmp(line, "Shared_Dirty:", 13) == 0) {
+ } else if (strncmp(field, "Shared_Dirty:", 13) == 0) {
stats->shared_dirty = strtoull(c, nullptr, 10);
- } else if (strncmp(line, "Swap:", 5) == 0) {
+ } else if (strncmp(field, "Swap:", 5) == 0) {
stats->swap = strtoull(c, nullptr, 10);
- } else if (strncmp(line, "SwapPss:", 8) == 0) {
+ } else if (strncmp(field, "SwapPss:", 8) == 0) {
stats->swap_pss = strtoull(c, nullptr, 10);
- } else if (strncmp(line, "ShmemPmdMapped:", 15) == 0) {
+ } else if (strncmp(field, "ShmemPmdMapped:", 15) == 0) {
stats->shmem_pmd_mapped = strtoull(c, nullptr, 10);
- } else if (strncmp(line, "Shared_Hugetlb:", 15) == 0) {
+ } else if (strncmp(field, "Shared_Hugetlb:", 15) == 0) {
stats->shared_hugetlb = strtoull(c, nullptr, 10);
}
break;
case 'R':
- if (strncmp(line, "Rss:", 4) == 0) {
+ if (strncmp(field, "Rss:", 4) == 0) {
stats->rss = strtoull(c, nullptr, 10);
}
break;
case 'A':
- if (strncmp(line, "AnonHugePages:", 14) == 0) {
+ if (strncmp(field, "AnonHugePages:", 14) == 0) {
stats->anon_huge_pages = strtoull(c, nullptr, 10);
}
break;
case 'F':
- if (strncmp(line, "FilePmdMapped:", 14) == 0) {
+ if (strncmp(field, "FilePmdMapped:", 14) == 0) {
stats->file_pmd_mapped = strtoull(c, nullptr, 10);
}
break;
@@ -386,6 +383,10 @@
size_t num_in_page_cache = 0;
size_t num_leftover_pages = num_pages;
for (size_t cur_page = first_page; cur_page < first_page + num_pages; ++cur_page) {
+ if (!get_wss) {
+ vma.usage.vss += pagesz;
+ }
+
// Cache page map data.
if (cur_page_cache_index == num_in_page_cache) {
static constexpr size_t kMaxPages = 2048;
@@ -478,9 +479,6 @@
vma.usage.shared_clean += is_dirty ? 0 : pagesz;
}
}
- if (!get_wss) {
- vma.usage.vss += pagesz * num_pages;
- }
return true;
}
diff --git a/sysmeminfo.cpp b/sysmeminfo.cpp
index b7a9c70..2dabea8 100644
--- a/sysmeminfo.cpp
+++ b/sysmeminfo.cpp
@@ -320,9 +320,11 @@
return true;
}
-bool ReadPerProcessGpuMem([[maybe_unused]] std::unordered_map<uint32_t, uint64_t>* out) {
+bool ReadGpuTotalUsageKb(uint64_t* size) {
#if defined(__ANDROID__) && !defined(__ANDROID_APEX__) && !defined(__ANDROID_VNDK__)
- static constexpr const char kBpfGpuMemTotalMap[] = "/sys/fs/bpf/map_gpu_mem_gpu_mem_total_map";
+ static constexpr const char kBpfGpuMemTotalMap[] =
+ "/sys/fs/bpf/map_gpu_mem_gpu_mem_total_map";
+ static constexpr uint64_t kBpfKeyGpuTotalUsage = 0;
// Use the read-only wrapper BpfMapRO to properly retrieve the read-only map.
auto map = bpf::BpfMapRO<uint64_t, uint64_t>(kBpfGpuMemTotalMap);
@@ -331,73 +333,14 @@
return false;
}
- if (!out) {
- LOG(ERROR) << "ReadPerProcessGpuMem: out param is null";
- return false;
- }
- out->clear();
-
- auto map_key = map.getFirstKey();
- if (!map_key.ok()) {
- return true;
- }
-
- do {
- uint64_t key = map_key.value();
- uint32_t pid = key; // BPF Key [32-bits GPU ID | 32-bits PID]
-
- auto gpu_mem = map.readValue(key);
- if (!gpu_mem.ok()) {
- LOG(ERROR) << "Invalid file format: " << kBpfGpuMemTotalMap;
- return false;
- }
-
- const auto& iter = out->find(pid);
- if (iter == out->end()) {
- out->insert({pid, gpu_mem.value() / 1024});
- } else {
- iter->second += gpu_mem.value() / 1024;
- }
-
- map_key = map.getNextKey(key);
- } while (map_key.ok());
-
- return true;
-#else
- return false;
-#endif
-}
-
-bool ReadProcessGpuUsageKb([[maybe_unused]] uint32_t pid, [[maybe_unused]] uint32_t gpu_id,
- uint64_t* size) {
-#if defined(__ANDROID__) && !defined(__ANDROID_APEX__) && !defined(__ANDROID_VNDK__)
- static constexpr const char kBpfGpuMemTotalMap[] = "/sys/fs/bpf/map_gpu_mem_gpu_mem_total_map";
-
- uint64_t gpu_mem;
-
- // BPF Key [32-bits GPU ID | 32-bits PID]
- uint64_t kBpfKeyGpuUsage = ((uint64_t)gpu_id << 32) | pid;
-
- // Use the read-only wrapper BpfMapRO to properly retrieve the read-only map.
- auto map = bpf::BpfMapRO<uint64_t, uint64_t>(kBpfGpuMemTotalMap);
- if (!map.isValid()) {
- LOG(ERROR) << "Can't open file: " << kBpfGpuMemTotalMap;
- return false;
- }
-
- auto res = map.readValue(kBpfKeyGpuUsage);
-
- if (res.ok()) {
- gpu_mem = res.value();
- } else if (res.error().code() == ENOENT) {
- gpu_mem = 0;
- } else {
+ auto res = map.readValue(kBpfKeyGpuTotalUsage);
+ if (!res.ok()) {
LOG(ERROR) << "Invalid file format: " << kBpfGpuMemTotalMap;
return false;
}
if (size) {
- *size = gpu_mem / 1024;
+ *size = res.value() / 1024;
}
return true;
#else
@@ -408,13 +351,5 @@
#endif
}
-bool ReadGpuTotalUsageKb(uint64_t* size) {
- // gpu_mem_total tracepoint defines PID 0 as global total
- // GPU ID 0 suffices for current android devices.
- // This will need to check all GPU IDs in future if more than
- // one is GPU device is present on the device.
- return ReadProcessGpuUsageKb(0, 0, size);
-}
-
} // namespace meminfo
} // namespace android
diff --git a/tools/Android.bp b/tools/Android.bp
index d336434..8cb98fc 100644
--- a/tools/Android.bp
+++ b/tools/Android.bp
@@ -55,7 +55,6 @@
shared_libs: [
"libbase",
"libmeminfo",
- "libprocinfo",
],
}
diff --git a/tools/procrank.cpp b/tools/procrank.cpp
index e4f247a..e7c1af9 100644
--- a/tools/procrank.cpp
+++ b/tools/procrank.cpp
@@ -25,7 +25,6 @@
#include <linux/oom.h>
#include <meminfo/procmeminfo.h>
#include <meminfo/sysmeminfo.h>
-#include <procinfo/process.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
@@ -33,9 +32,7 @@
#include <iostream>
#include <memory>
-#include <set>
#include <sstream>
-#include <unordered_map>
#include <vector>
using ::android::meminfo::MemUsage;
@@ -145,7 +142,7 @@
uint64_t total_zswap = 0;
[[noreturn]] static void usage(int exit_status) {
- std::cerr << "Usage: " << getprogname() << " [ -W ] [ -v | -r | -p | -u | -s | -h ] [-d PID]"
+ std::cerr << "Usage: " << getprogname() << " [ -W ] [ -v | -r | -p | -u | -s | -h ]"
<< std::endl
<< " -v Sort by VSS." << std::endl
<< " -r Sort by RSS." << std::endl
@@ -158,15 +155,14 @@
<< " -C Only show non-cached (ram/swap backed) pages" << std::endl
<< " -k Only show pages collapsed by KSM" << std::endl
<< " -w Display statistics for working set only." << std::endl
- << " -W Reset working set of processes." << std::endl
+ << " -W Reset working set of all processes." << std::endl
<< " -o Show and sort by oom score against lowmemorykiller thresholds."
<< std::endl
- << " -d Filter to descendants of specified process (can be repeated)" << std::endl
<< " -h Display this help screen." << std::endl;
exit(exit_status);
}
-static bool read_all_pids(std::set<pid_t>* pids) {
+static bool read_all_pids(std::vector<pid_t>* pids, std::function<bool(pid_t pid)> for_each_pid) {
pids->clear();
std::unique_ptr<DIR, int (*)(DIR*)> procdir(opendir("/proc"), closedir);
if (!procdir) return false;
@@ -175,7 +171,8 @@
pid_t pid;
while ((dir = readdir(procdir.get()))) {
if (!::android::base::ParseInt(dir->d_name, &pid)) continue;
- pids->insert(pid);
+ if (!for_each_pid(pid)) return false;
+ pids->emplace_back(pid);
}
return true;
@@ -378,9 +375,8 @@
uint64_t pgflags = 0;
uint64_t pgflags_mask = 0;
- std::vector<pid_t> descendant_filter;
int opt;
- while ((opt = getopt(argc, argv, "cCd:hkoprRsuvwW")) != -1) {
+ while ((opt = getopt(argc, argv, "cChkoprRsuvwW")) != -1) {
switch (opt) {
case 'c':
pgflags = 0;
@@ -390,15 +386,6 @@
pgflags = (1 << KPF_SWAPBACKED);
pgflags_mask = (1 << KPF_SWAPBACKED);
break;
- case 'd': {
- pid_t p;
- if (!android::base::ParseInt(optarg, &p)) {
- std::cerr << "Failed to parse pid '" << optarg << "'" << std::endl;
- usage(EXIT_FAILURE);
- }
- descendant_filter.push_back(p);
- break;
- }
case 'h':
usage(EXIT_SUCCESS);
case 'k':
@@ -438,58 +425,13 @@
}
}
- std::set<pid_t> pids;
+ std::vector<pid_t> pids;
std::vector<ProcessRecord> procs;
- if (!read_all_pids(&pids)) {
- std::cerr << "Failed to read pids" << std::endl;
- exit(EXIT_FAILURE);
- }
-
- if (descendant_filter.size()) {
- // Map from parent pid to all of its children.
- std::unordered_map<pid_t, std::vector<pid_t>> pid_tree;
-
- for (pid_t pid : pids) {
- android::procinfo::ProcessInfo info;
- std::string error;
- if (!android::procinfo::GetProcessInfo(pid, &info, &error)) {
- std::cerr << "warning: failed to get process info for: " << pid << ": " << error
- << std::endl;
- continue;
- }
-
- pid_tree[info.ppid].push_back(pid);
- }
-
- std::set<pid_t> final_pids;
- std::vector<pid_t>& frontier = descendant_filter;
-
- // Do a breadth-first walk of the process tree, starting from the pids we were given.
- while (!frontier.empty()) {
- pid_t pid = frontier.back();
- frontier.pop_back();
-
- // It's possible for the pid we're looking at to already be in our list if one of the
- // passed in processes descends from another, or if the same pid is passed twice.
- auto [it, inserted] = final_pids.insert(pid);
- if (inserted) {
- auto it = pid_tree.find(pid);
- if (it != pid_tree.end()) {
- // Add all of the children of |pid| to the list of nodes to visit.
- frontier.insert(frontier.end(), it->second.begin(), it->second.end());
- }
- }
- }
-
- pids = std::move(final_pids);
- }
-
if (reset_wss) {
- for (pid_t pid : pids) {
- if (!ProcMemInfo::ResetWorkingSet(pid)) {
- std::cerr << "Failed to reset working set of all processes" << std::endl;
- exit(EXIT_FAILURE);
- }
+ if (!read_all_pids(&pids,
+ [&](pid_t pid) -> bool { return ProcMemInfo::ResetWorkingSet(pid); })) {
+ std::cerr << "Failed to reset working set of all processes" << std::endl;
+ exit(EXIT_FAILURE);
}
// we are done, all other options passed to procrank are ignored in the presence of '-W'
return 0;
@@ -514,35 +456,42 @@
}
}
- // Mark each swap offset used by the process as we find them for calculating proportional
- // swap usage later.
- for (pid_t pid : pids) {
+ auto mark_swap_usage = [&](pid_t pid) -> bool {
ProcessRecord proc(pid, show_wss, pgflags, pgflags_mask);
if (!proc.valid()) {
// Check to see if the process is still around, skip the process if the proc
// directory is inaccessible. It was most likely killed while creating the process
// record
std::string procdir = ::android::base::StringPrintf("/proc/%d", pid);
- if (access(procdir.c_str(), F_OK | R_OK)) continue;
+ if (access(procdir.c_str(), F_OK | R_OK)) return true;
// Warn if we failed to gather process stats even while it is still alive.
// Return success here, so we continue to print stats for other processes.
std::cerr << "warning: failed to create process record for: " << pid << std::endl;
- continue;
+ return true;
}
// Skip processes with no memory mappings
uint64_t vss = show_wss ? proc.Wss().vss : proc.Usage().vss;
- if (vss == 0) continue;
+ if (vss == 0) return true;
// collect swap_offset counts from all processes in 1st pass
- if (!show_wss && has_swap && !count_swap_offsets(proc, swap_offset_array)) {
+ if (!show_wss && has_swap &&
+ !count_swap_offsets(proc, swap_offset_array)) {
std::cerr << "Failed to count swap offsets for process: " << pid << std::endl;
- std::cerr << "Failed to read all pids from the system" << std::endl;
- exit(EXIT_FAILURE);
+ return false;
}
procs.emplace_back(std::move(proc));
+ return true;
+ };
+
+ // Get a list of all pids currently running in the system in 1st pass through all processes.
+ // Mark each swap offset used by the process as we find them for calculating proportional
+ // swap usage later.
+ if (!read_all_pids(&pids, mark_swap_usage)) {
+ std::cerr << "Failed to read all pids from the system" << std::endl;
+ exit(EXIT_FAILURE);
}
std::stringstream ss;
diff --git a/tools/showmap.cpp b/tools/showmap.cpp
index 452e895..36739b1 100644
--- a/tools/showmap.cpp
+++ b/tools/showmap.cpp
@@ -16,10 +16,10 @@
#include <getopt.h>
#include <inttypes.h>
-#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
+#include <sys/signal.h>
#include <sys/types.h>
#include <unistd.h>
diff --git a/vts/Android.bp b/vts/Android.bp
index ec7f58a..0f514b5 100644
--- a/vts/Android.bp
+++ b/vts/Android.bp
@@ -34,7 +34,5 @@
defaults: ["vts_meminfo_defaults"],
test_suites: ["vts"],
require_root: true,
- test_options: {
- min_shipping_api_level: 29,
- },
+ test_min_api_level: 29,
}
diff --git a/vts/vts_meminfo_test.cpp b/vts/vts_meminfo_test.cpp
index cec46d5..a9b2c26 100644
--- a/vts/vts_meminfo_test.cpp
+++ b/vts/vts_meminfo_test.cpp
@@ -94,7 +94,7 @@
TEST(SysMemInfo, TestGpuTotalUsageKb) {
uint64_t size;
- if (android::base::GetIntProperty("ro.vendor.api_level", 0) < __ANDROID_API_S__) {
+ if (android::base::GetIntProperty("ro.product.first_api_level", 0) < __ANDROID_API_S__) {
GTEST_SKIP();
}