Snap for 5726885 from e818cccd58f3c550ef92c8e0e9ddffbf8916c336 to qt-qpr1-release

Change-Id: I571deedb1a0159d6a1b9a51c2f28b81bc23fbc7d
diff --git a/libmeminfo/pageacct.cpp b/libmeminfo/pageacct.cpp
index 0a26c08..cb17af8 100644
--- a/libmeminfo/pageacct.cpp
+++ b/libmeminfo/pageacct.cpp
@@ -81,7 +81,8 @@
         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;
     }
@@ -95,7 +96,8 @@
         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;
     }
@@ -130,7 +132,7 @@
     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;
     }
diff --git a/libmeminfo/procmeminfo.cpp b/libmeminfo/procmeminfo.cpp
index 934d65c..a8b43c1 100644
--- a/libmeminfo/procmeminfo.cpp
+++ b/libmeminfo/procmeminfo.cpp
@@ -27,6 +27,7 @@
 #include <memory>
 #include <string>
 #include <utility>
+#include <vector>
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
@@ -278,68 +279,89 @@
 
 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_;
+    if (get_wss && use_pageidle && !pinfo.InitPageAcct(true)) {
+        LOG(ERROR) << "Failed to init idle page accounting";
         return false;
     }
 
-    if (get_wss && use_pageidle) {
-        if (!pinfo.InitPageAcct(true)) {
-            LOG(ERROR) << "Failed to init idle page accounting";
-            return false;
-        }
-    }
+    uint64_t pagesz = getpagesize();
+    size_t num_pages = (vma.end - vma.start) / pagesz;
+    size_t first_page = vma.start / pagesz;
 
-    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) {
+    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;
             }
@@ -351,7 +373,7 @@
 
         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;
diff --git a/libmeminfo/tools/procrank.cpp b/libmeminfo/tools/procrank.cpp
index cb3757d..1e44ff9 100644
--- a/libmeminfo/tools/procrank.cpp
+++ b/libmeminfo/tools/procrank.cpp
@@ -348,7 +348,7 @@
     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) {
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index c2ee061..7c5a466 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -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) */
@@ -551,6 +552,49 @@
            (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];
@@ -559,6 +603,7 @@
     struct lmk_procprio params;
     bool is_system_server;
     struct passwd *pwdrec;
+    int tgid;
 
     lmkd_pack_get_procprio(packet, &params);
 
@@ -568,6 +613,14 @@
         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 */
@@ -1332,6 +1385,7 @@
 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;
@@ -1345,6 +1399,12 @@
     (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;