Loading libmeminfo/pageacct.cpp +5 −3 Original line number Diff line number Diff line Loading @@ -81,7 +81,8 @@ bool PageAcct::PageFlags(uint64_t pfn, uint64_t* flags) { if (!InitPageAcct()) return false; } if (pread64(kpageflags_fd_, flags, sizeof(uint64_t), pfn * sizeof(uint64_t)) < 0) { if (pread64(kpageflags_fd_, flags, sizeof(uint64_t), pfn * sizeof(uint64_t)) != sizeof(uint64_t)) { PLOG(ERROR) << "Failed to read page flags for page " << pfn; return false; } Loading @@ -95,7 +96,8 @@ bool PageAcct::PageMapCount(uint64_t pfn, uint64_t* mapcount) { if (!InitPageAcct()) return false; } if (pread64(kpagecount_fd_, mapcount, sizeof(uint64_t), pfn * sizeof(uint64_t)) < 0) { if (pread64(kpagecount_fd_, mapcount, sizeof(uint64_t), pfn * sizeof(uint64_t)) != sizeof(uint64_t)) { PLOG(ERROR) << "Failed to read map count for page " << pfn; return false; } Loading Loading @@ -130,7 +132,7 @@ int PageAcct::GetPageIdle(uint64_t pfn) const { off64_t offset = pfn_to_idle_bitmap_offset(pfn); uint64_t idle_bits; if (pread64(pageidle_fd_, &idle_bits, sizeof(uint64_t), offset) < 0) { if (pread64(pageidle_fd_, &idle_bits, sizeof(uint64_t), offset) != sizeof(uint64_t)) { PLOG(ERROR) << "Failed to read page idle bitmap for page " << pfn; return -errno; } Loading libmeminfo/procmeminfo.cpp +55 −33 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include <memory> #include <string> #include <utility> #include <vector> #include <android-base/file.h> #include <android-base/logging.h> Loading Loading @@ -278,68 +279,89 @@ bool ProcMemInfo::ReadMaps(bool get_wss, bool use_pageidle) { bool ProcMemInfo::ReadVmaStats(int pagemap_fd, Vma& vma, bool get_wss, bool use_pageidle) { PageAcct& pinfo = PageAcct::Instance(); uint64_t pagesz = getpagesize(); uint64_t num_pages = (vma.end - vma.start) / pagesz; std::unique_ptr<uint64_t[]> pg_frames(new uint64_t[num_pages]); uint64_t first = vma.start / pagesz; if (pread64(pagemap_fd, pg_frames.get(), num_pages * sizeof(uint64_t), first * sizeof(uint64_t)) < 0) { PLOG(ERROR) << "Failed to read page frames from page map for pid: " << pid_; return false; } if (get_wss && use_pageidle) { if (!pinfo.InitPageAcct(true)) { if (get_wss && use_pageidle && !pinfo.InitPageAcct(true)) { LOG(ERROR) << "Failed to init idle page accounting"; return false; } } std::unique_ptr<uint64_t[]> pg_flags(new uint64_t[num_pages]); std::unique_ptr<uint64_t[]> pg_counts(new uint64_t[num_pages]); for (uint64_t i = 0; i < num_pages; ++i) { uint64_t pagesz = getpagesize(); size_t num_pages = (vma.end - vma.start) / pagesz; size_t first_page = vma.start / pagesz; std::vector<uint64_t> page_cache; size_t cur_page_cache_index = 0; 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; } uint64_t p = pg_frames[i]; if (!PAGE_PRESENT(p) && !PAGE_SWAPPED(p)) continue; if (PAGE_SWAPPED(p)) { // Cache page map data. if (cur_page_cache_index == num_in_page_cache) { static constexpr size_t kMaxPages = 2048; num_leftover_pages -= num_in_page_cache; if (num_leftover_pages > kMaxPages) { num_in_page_cache = kMaxPages; } else { num_in_page_cache = num_leftover_pages; } page_cache.resize(num_in_page_cache); size_t total_bytes = page_cache.size() * sizeof(uint64_t); ssize_t bytes = pread64(pagemap_fd, page_cache.data(), total_bytes, cur_page * sizeof(uint64_t)); if (bytes != total_bytes) { if (bytes == -1) { PLOG(ERROR) << "Failed to read page data at offset 0x" << std::hex << cur_page * sizeof(uint64_t); } else { LOG(ERROR) << "Failed to read page data at offset 0x" << std::hex << cur_page * sizeof(uint64_t) << std::dec << " read bytes " << bytes << " expected bytes " << total_bytes; } return false; } cur_page_cache_index = 0; } uint64_t page_info = page_cache[cur_page_cache_index++]; if (!PAGE_PRESENT(page_info) && !PAGE_SWAPPED(page_info)) continue; if (PAGE_SWAPPED(page_info)) { vma.usage.swap += pagesz; swap_offsets_.emplace_back(PAGE_SWAP_OFFSET(p)); swap_offsets_.emplace_back(PAGE_SWAP_OFFSET(page_info)); continue; } uint64_t page_frame = PAGE_PFN(p); if (!pinfo.PageFlags(page_frame, &pg_flags[i])) { uint64_t page_frame = PAGE_PFN(page_info); uint64_t cur_page_flags; if (!pinfo.PageFlags(page_frame, &cur_page_flags)) { LOG(ERROR) << "Failed to get page flags for " << page_frame << " in process " << pid_; swap_offsets_.clear(); return false; } // skip unwanted pages from the count if ((pg_flags[i] & pgflags_mask_) != pgflags_) continue; if ((cur_page_flags & pgflags_mask_) != pgflags_) continue; if (!pinfo.PageMapCount(page_frame, &pg_counts[i])) { uint64_t cur_page_counts; if (!pinfo.PageMapCount(page_frame, &cur_page_counts)) { LOG(ERROR) << "Failed to get page count for " << page_frame << " in process " << pid_; swap_offsets_.clear(); return false; } // Page was unmapped between the presence check at the beginning of the loop and here. if (pg_counts[i] == 0) { pg_frames[i] = 0; pg_flags[i] = 0; if (cur_page_counts == 0) { continue; } bool is_dirty = !!(pg_flags[i] & (1 << KPF_DIRTY)); bool is_private = (pg_counts[i] == 1); bool is_dirty = !!(cur_page_flags & (1 << KPF_DIRTY)); bool is_private = (cur_page_counts == 1); // Working set if (get_wss) { bool is_referenced = use_pageidle ? (pinfo.IsPageIdle(page_frame) == 1) : !!(pg_flags[i] & (1 << KPF_REFERENCED)); : !!(cur_page_flags & (1 << KPF_REFERENCED)); if (!is_referenced) { continue; } Loading @@ -351,7 +373,7 @@ bool ProcMemInfo::ReadVmaStats(int pagemap_fd, Vma& vma, bool get_wss, bool use_ vma.usage.rss += pagesz; vma.usage.uss += is_private ? pagesz : 0; vma.usage.pss += pagesz / pg_counts[i]; vma.usage.pss += pagesz / cur_page_counts; if (is_private) { vma.usage.private_dirty += is_dirty ? pagesz : 0; vma.usage.private_clean += is_dirty ? 0 : pagesz; Loading libmeminfo/tools/procrank.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -348,7 +348,7 @@ int main(int argc, char* argv[]) { auto rss_sort = [](ProcessRecord& a, ProcessRecord& b) { MemUsage stats_a = show_wss ? a.Wss() : a.Usage(); MemUsage stats_b = show_wss ? b.Wss() : b.Usage(); return reverse_sort ? stats_a.rss < stats_b.pss : stats_a.pss > stats_b.pss; return reverse_sort ? stats_a.rss < stats_b.rss : stats_a.rss > stats_b.rss; }; auto vss_sort = [](ProcessRecord& a, ProcessRecord& b) { Loading lmkd/lmkd.c +60 −0 Original line number Diff line number Diff line Loading @@ -79,6 +79,7 @@ #define MEMCG_MEMORYSW_USAGE "/dev/memcg/memory.memsw.usage_in_bytes" #define ZONEINFO_PATH "/proc/zoneinfo" #define MEMINFO_PATH "/proc/meminfo" #define PROC_STATUS_TGID_FIELD "Tgid:" #define LINE_MAX 128 /* Android Logger event logtags (see event.logtags) */ Loading Loading @@ -551,6 +552,49 @@ static inline long get_time_diff_ms(struct timespec *from, (to->tv_nsec - from->tv_nsec) / (long)NS_PER_MS; } static int proc_get_tgid(int pid) { char path[PATH_MAX]; char buf[PAGE_SIZE]; int fd; ssize_t size; char *pos; int64_t tgid = -1; snprintf(path, PATH_MAX, "/proc/%d/status", pid); fd = open(path, O_RDONLY | O_CLOEXEC); if (fd < 0) { return -1; } size = read_all(fd, buf, sizeof(buf) - 1); if (size < 0) { goto out; } buf[size] = 0; pos = buf; while (true) { pos = strstr(pos, PROC_STATUS_TGID_FIELD); /* Stop if TGID tag not found or found at the line beginning */ if (pos == NULL || pos == buf || pos[-1] == '\n') { break; } pos++; } if (pos == NULL) { goto out; } pos += strlen(PROC_STATUS_TGID_FIELD); while (*pos == ' ') pos++; parse_int64(pos, &tgid); out: close(fd); return (int)tgid; } static void cmd_procprio(LMKD_CTRL_PACKET packet) { struct proc *procp; char path[80]; Loading @@ -559,6 +603,7 @@ static void cmd_procprio(LMKD_CTRL_PACKET packet) { struct lmk_procprio params; bool is_system_server; struct passwd *pwdrec; int tgid; lmkd_pack_get_procprio(packet, ¶ms); Loading @@ -568,6 +613,14 @@ static void cmd_procprio(LMKD_CTRL_PACKET packet) { return; } /* Check if registered process is a thread group leader */ tgid = proc_get_tgid(params.pid); if (tgid >= 0 && tgid != params.pid) { ALOGE("Attempt to register a task that is not a thread group leader (tid %d, tgid %d)", params.pid, tgid); return; } /* gid containing AID_READPROC required */ /* CAP_SYS_RESOURCE required */ /* CAP_DAC_OVERRIDE required */ Loading Loading @@ -1332,6 +1385,7 @@ static int last_killed_pid = -1; static int kill_one_process(struct proc* procp, int min_oom_score) { int pid = procp->pid; uid_t uid = procp->uid; int tgid; char *taskname; int tasksize; int r; Loading @@ -1345,6 +1399,12 @@ static int kill_one_process(struct proc* procp, int min_oom_score) { (void)(min_oom_score); #endif tgid = proc_get_tgid(pid); if (tgid >= 0 && tgid != pid) { ALOGE("Possible pid reuse detected (pid %d, tgid %d)!", pid, tgid); goto out; } taskname = proc_get_name(pid); if (!taskname) { goto out; Loading Loading
libmeminfo/pageacct.cpp +5 −3 Original line number Diff line number Diff line Loading @@ -81,7 +81,8 @@ bool PageAcct::PageFlags(uint64_t pfn, uint64_t* flags) { if (!InitPageAcct()) return false; } if (pread64(kpageflags_fd_, flags, sizeof(uint64_t), pfn * sizeof(uint64_t)) < 0) { if (pread64(kpageflags_fd_, flags, sizeof(uint64_t), pfn * sizeof(uint64_t)) != sizeof(uint64_t)) { PLOG(ERROR) << "Failed to read page flags for page " << pfn; return false; } Loading @@ -95,7 +96,8 @@ bool PageAcct::PageMapCount(uint64_t pfn, uint64_t* mapcount) { if (!InitPageAcct()) return false; } if (pread64(kpagecount_fd_, mapcount, sizeof(uint64_t), pfn * sizeof(uint64_t)) < 0) { if (pread64(kpagecount_fd_, mapcount, sizeof(uint64_t), pfn * sizeof(uint64_t)) != sizeof(uint64_t)) { PLOG(ERROR) << "Failed to read map count for page " << pfn; return false; } Loading Loading @@ -130,7 +132,7 @@ int PageAcct::GetPageIdle(uint64_t pfn) const { off64_t offset = pfn_to_idle_bitmap_offset(pfn); uint64_t idle_bits; if (pread64(pageidle_fd_, &idle_bits, sizeof(uint64_t), offset) < 0) { if (pread64(pageidle_fd_, &idle_bits, sizeof(uint64_t), offset) != sizeof(uint64_t)) { PLOG(ERROR) << "Failed to read page idle bitmap for page " << pfn; return -errno; } Loading
libmeminfo/procmeminfo.cpp +55 −33 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include <memory> #include <string> #include <utility> #include <vector> #include <android-base/file.h> #include <android-base/logging.h> Loading Loading @@ -278,68 +279,89 @@ bool ProcMemInfo::ReadMaps(bool get_wss, bool use_pageidle) { bool ProcMemInfo::ReadVmaStats(int pagemap_fd, Vma& vma, bool get_wss, bool use_pageidle) { PageAcct& pinfo = PageAcct::Instance(); uint64_t pagesz = getpagesize(); uint64_t num_pages = (vma.end - vma.start) / pagesz; std::unique_ptr<uint64_t[]> pg_frames(new uint64_t[num_pages]); uint64_t first = vma.start / pagesz; if (pread64(pagemap_fd, pg_frames.get(), num_pages * sizeof(uint64_t), first * sizeof(uint64_t)) < 0) { PLOG(ERROR) << "Failed to read page frames from page map for pid: " << pid_; return false; } if (get_wss && use_pageidle) { if (!pinfo.InitPageAcct(true)) { if (get_wss && use_pageidle && !pinfo.InitPageAcct(true)) { LOG(ERROR) << "Failed to init idle page accounting"; return false; } } std::unique_ptr<uint64_t[]> pg_flags(new uint64_t[num_pages]); std::unique_ptr<uint64_t[]> pg_counts(new uint64_t[num_pages]); for (uint64_t i = 0; i < num_pages; ++i) { uint64_t pagesz = getpagesize(); size_t num_pages = (vma.end - vma.start) / pagesz; size_t first_page = vma.start / pagesz; std::vector<uint64_t> page_cache; size_t cur_page_cache_index = 0; 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; } uint64_t p = pg_frames[i]; if (!PAGE_PRESENT(p) && !PAGE_SWAPPED(p)) continue; if (PAGE_SWAPPED(p)) { // Cache page map data. if (cur_page_cache_index == num_in_page_cache) { static constexpr size_t kMaxPages = 2048; num_leftover_pages -= num_in_page_cache; if (num_leftover_pages > kMaxPages) { num_in_page_cache = kMaxPages; } else { num_in_page_cache = num_leftover_pages; } page_cache.resize(num_in_page_cache); size_t total_bytes = page_cache.size() * sizeof(uint64_t); ssize_t bytes = pread64(pagemap_fd, page_cache.data(), total_bytes, cur_page * sizeof(uint64_t)); if (bytes != total_bytes) { if (bytes == -1) { PLOG(ERROR) << "Failed to read page data at offset 0x" << std::hex << cur_page * sizeof(uint64_t); } else { LOG(ERROR) << "Failed to read page data at offset 0x" << std::hex << cur_page * sizeof(uint64_t) << std::dec << " read bytes " << bytes << " expected bytes " << total_bytes; } return false; } cur_page_cache_index = 0; } uint64_t page_info = page_cache[cur_page_cache_index++]; if (!PAGE_PRESENT(page_info) && !PAGE_SWAPPED(page_info)) continue; if (PAGE_SWAPPED(page_info)) { vma.usage.swap += pagesz; swap_offsets_.emplace_back(PAGE_SWAP_OFFSET(p)); swap_offsets_.emplace_back(PAGE_SWAP_OFFSET(page_info)); continue; } uint64_t page_frame = PAGE_PFN(p); if (!pinfo.PageFlags(page_frame, &pg_flags[i])) { uint64_t page_frame = PAGE_PFN(page_info); uint64_t cur_page_flags; if (!pinfo.PageFlags(page_frame, &cur_page_flags)) { LOG(ERROR) << "Failed to get page flags for " << page_frame << " in process " << pid_; swap_offsets_.clear(); return false; } // skip unwanted pages from the count if ((pg_flags[i] & pgflags_mask_) != pgflags_) continue; if ((cur_page_flags & pgflags_mask_) != pgflags_) continue; if (!pinfo.PageMapCount(page_frame, &pg_counts[i])) { uint64_t cur_page_counts; if (!pinfo.PageMapCount(page_frame, &cur_page_counts)) { LOG(ERROR) << "Failed to get page count for " << page_frame << " in process " << pid_; swap_offsets_.clear(); return false; } // Page was unmapped between the presence check at the beginning of the loop and here. if (pg_counts[i] == 0) { pg_frames[i] = 0; pg_flags[i] = 0; if (cur_page_counts == 0) { continue; } bool is_dirty = !!(pg_flags[i] & (1 << KPF_DIRTY)); bool is_private = (pg_counts[i] == 1); bool is_dirty = !!(cur_page_flags & (1 << KPF_DIRTY)); bool is_private = (cur_page_counts == 1); // Working set if (get_wss) { bool is_referenced = use_pageidle ? (pinfo.IsPageIdle(page_frame) == 1) : !!(pg_flags[i] & (1 << KPF_REFERENCED)); : !!(cur_page_flags & (1 << KPF_REFERENCED)); if (!is_referenced) { continue; } Loading @@ -351,7 +373,7 @@ bool ProcMemInfo::ReadVmaStats(int pagemap_fd, Vma& vma, bool get_wss, bool use_ vma.usage.rss += pagesz; vma.usage.uss += is_private ? pagesz : 0; vma.usage.pss += pagesz / pg_counts[i]; vma.usage.pss += pagesz / cur_page_counts; if (is_private) { vma.usage.private_dirty += is_dirty ? pagesz : 0; vma.usage.private_clean += is_dirty ? 0 : pagesz; Loading
libmeminfo/tools/procrank.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -348,7 +348,7 @@ int main(int argc, char* argv[]) { auto rss_sort = [](ProcessRecord& a, ProcessRecord& b) { MemUsage stats_a = show_wss ? a.Wss() : a.Usage(); MemUsage stats_b = show_wss ? b.Wss() : b.Usage(); return reverse_sort ? stats_a.rss < stats_b.pss : stats_a.pss > stats_b.pss; return reverse_sort ? stats_a.rss < stats_b.rss : stats_a.rss > stats_b.rss; }; auto vss_sort = [](ProcessRecord& a, ProcessRecord& b) { Loading
lmkd/lmkd.c +60 −0 Original line number Diff line number Diff line Loading @@ -79,6 +79,7 @@ #define MEMCG_MEMORYSW_USAGE "/dev/memcg/memory.memsw.usage_in_bytes" #define ZONEINFO_PATH "/proc/zoneinfo" #define MEMINFO_PATH "/proc/meminfo" #define PROC_STATUS_TGID_FIELD "Tgid:" #define LINE_MAX 128 /* Android Logger event logtags (see event.logtags) */ Loading Loading @@ -551,6 +552,49 @@ static inline long get_time_diff_ms(struct timespec *from, (to->tv_nsec - from->tv_nsec) / (long)NS_PER_MS; } static int proc_get_tgid(int pid) { char path[PATH_MAX]; char buf[PAGE_SIZE]; int fd; ssize_t size; char *pos; int64_t tgid = -1; snprintf(path, PATH_MAX, "/proc/%d/status", pid); fd = open(path, O_RDONLY | O_CLOEXEC); if (fd < 0) { return -1; } size = read_all(fd, buf, sizeof(buf) - 1); if (size < 0) { goto out; } buf[size] = 0; pos = buf; while (true) { pos = strstr(pos, PROC_STATUS_TGID_FIELD); /* Stop if TGID tag not found or found at the line beginning */ if (pos == NULL || pos == buf || pos[-1] == '\n') { break; } pos++; } if (pos == NULL) { goto out; } pos += strlen(PROC_STATUS_TGID_FIELD); while (*pos == ' ') pos++; parse_int64(pos, &tgid); out: close(fd); return (int)tgid; } static void cmd_procprio(LMKD_CTRL_PACKET packet) { struct proc *procp; char path[80]; Loading @@ -559,6 +603,7 @@ static void cmd_procprio(LMKD_CTRL_PACKET packet) { struct lmk_procprio params; bool is_system_server; struct passwd *pwdrec; int tgid; lmkd_pack_get_procprio(packet, ¶ms); Loading @@ -568,6 +613,14 @@ static void cmd_procprio(LMKD_CTRL_PACKET packet) { return; } /* Check if registered process is a thread group leader */ tgid = proc_get_tgid(params.pid); if (tgid >= 0 && tgid != params.pid) { ALOGE("Attempt to register a task that is not a thread group leader (tid %d, tgid %d)", params.pid, tgid); return; } /* gid containing AID_READPROC required */ /* CAP_SYS_RESOURCE required */ /* CAP_DAC_OVERRIDE required */ Loading Loading @@ -1332,6 +1385,7 @@ static int last_killed_pid = -1; static int kill_one_process(struct proc* procp, int min_oom_score) { int pid = procp->pid; uid_t uid = procp->uid; int tgid; char *taskname; int tasksize; int r; Loading @@ -1345,6 +1399,12 @@ static int kill_one_process(struct proc* procp, int min_oom_score) { (void)(min_oom_score); #endif tgid = proc_get_tgid(pid); if (tgid >= 0 && tgid != pid) { ALOGE("Possible pid reuse detected (pid %d, tgid %d)!", pid, tgid); goto out; } taskname = proc_get_name(pid); if (!taskname) { goto out; Loading