Snap for 10453563 from a36da3bd16a5e4bde39e4ec2b10e4ddc1390a10d to mainline-os-statsd-release

Change-Id: I7dd06218947c5e120b90239e6206f9d4aa63836c
diff --git a/TEST_MAPPING b/TEST_MAPPING
index ef6fb27..180859b 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -4,7 +4,7 @@
       "name": "libprocinfo_test"
     }
   ],
-  "hwasan-postsubmit": [
+  "hwasan-presubmit": [
     {
       "name": "libprocinfo_test"
     }
diff --git a/include/procinfo/process.h b/include/procinfo/process.h
index ee245e4..92d5997 100644
--- a/include/procinfo/process.h
+++ b/include/procinfo/process.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <dirent.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <stdlib.h>
 #include <sys/types.h>
@@ -29,6 +30,7 @@
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/parseint.h>
+#include <android-base/stringprintf.h>
 #include <android-base/unique_fd.h>
 
 namespace android {
@@ -59,12 +61,15 @@
   uint64_t starttime;
 };
 
+bool SetError(std::string* error, int errno_value, const char* fmt, ...);
+
 // Parse the contents of /proc/<tid>/status into |process_info|.
 bool GetProcessInfo(pid_t tid, ProcessInfo* process_info, std::string* error = nullptr);
 
 // Parse the contents of <fd>/status into |process_info|.
 // |fd| should be an fd pointing at a /proc/<pid> directory.
-bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info, std::string* error = nullptr);
+// |pid| is used for error messages.
+bool GetProcessInfoFromProcPidFd(int fd, int pid, ProcessInfo* process_info, std::string* error = nullptr);
 
 // Fetch the list of threads from a given process's /proc/<pid> directory.
 // |fd| should be an fd pointing at a /proc/<pid> directory.
@@ -76,10 +81,7 @@
   int task_fd = openat(fd, "task", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
   std::unique_ptr<DIR, int (*)(DIR*)> dir(fdopendir(task_fd), closedir);
   if (!dir) {
-    if (error != nullptr) {
-      *error = "failed to open task directory";
-    }
-    return false;
+    return SetError(error, errno, "failed to open task directory");
   }
 
   struct dirent* dent;
@@ -87,10 +89,7 @@
     if (strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0) {
       pid_t tid;
       if (!android::base::ParseInt(dent->d_name, &tid, 1, std::numeric_limits<pid_t>::max())) {
-        if (error != nullptr) {
-          *error = std::string("failed to parse task id: ") + dent->d_name;
-        }
-        return false;
+        return SetError(error, 0, "failed to parse task id %s", dent->d_name);
       }
 
       out->insert(out->end(), tid);
@@ -103,20 +102,11 @@
 template <typename Collection>
 auto GetProcessTids(pid_t pid, Collection* out, std::string* error = nullptr) ->
     typename std::enable_if<sizeof(typename Collection::value_type) >= sizeof(pid_t), bool>::type {
-  char task_path[PATH_MAX];
-  if (snprintf(task_path, PATH_MAX, "/proc/%d", pid) >= PATH_MAX) {
-    if (error != nullptr) {
-      *error = "task path overflow (pid = " + std::to_string(pid) + ")";
-    }
-    return false;
-  }
-
+  char task_path[32];
+  snprintf(task_path, sizeof(task_path), "/proc/%d", pid);
   android::base::unique_fd fd(open(task_path, O_DIRECTORY | O_RDONLY | O_CLOEXEC));
   if (fd == -1) {
-    if (error != nullptr) {
-      *error = std::string("failed to open ") + task_path;
-    }
-    return false;
+    return SetError(error, errno, "failed to open %s", task_path);
   }
 
   return GetProcessTidsFromProcPidFd(fd.get(), out, error);
diff --git a/include/procinfo/process_map.h b/include/procinfo/process_map.h
index d8a563c..3c9d144 100644
--- a/include/procinfo/process_map.h
+++ b/include/procinfo/process_map.h
@@ -83,15 +83,15 @@
   return true;
 }
 
-// Parses a line given p pointing at proc/<pid>/maps content buffer and returns true on success
-// and false on failure parsing. The next end of line will be replaced by null character and the
-// immediate offset after the parsed line will be returned in next_line.
+// Parses the given line p pointing at proc/<pid>/maps content buffer and returns true on success
+// and false on failure parsing. The first new line character of line will be replaced by the
+// null character and *next_line will point to the character after the null.
 //
 // Example of how a parsed line look line:
 // 00400000-00409000 r-xp 00000000 fc:00 426998  /usr/lib/gvfs/gvfsd-http
 static inline bool ParseMapsFileLine(char* p, uint64_t& start_addr, uint64_t& end_addr, uint16_t& flags,
                       uint64_t& pgoff, ino_t& inode, char** name, bool& shared, char** next_line) {
-  // Make end of line be null
+  // Make the first new line character null.
   *next_line = strchr(p, '\n');
   if (*next_line != nullptr) {
     **next_line = '\0';
@@ -167,6 +167,7 @@
     return false;
   }
 
+  // Assumes that the first new character was replaced with null.
   *name = p;
 
   return true;
@@ -229,21 +230,33 @@
   return ReadMapFileContent(&content[0], callback);
 }
 
+
+inline bool ReadMapFile(const std::string& map_file, const MapInfoParamsCallback& callback,
+                        std::string& mapsBuffer) {
+  if (!android::base::ReadFileToString(map_file, &mapsBuffer)) {
+    return false;
+  }
+  return ReadMapFileContent(&mapsBuffer[0], callback);
+}
+
 inline bool ReadMapFile(const std::string& map_file,
                 const MapInfoParamsCallback& callback) {
   std::string content;
-  if (!android::base::ReadFileToString(map_file, &content)) {
-    return false;
-  }
-  return ReadMapFileContent(&content[0], callback);
+  return ReadMapFile(map_file, callback, content);
 }
 
 inline bool ReadProcessMaps(pid_t pid, const MapInfoCallback& callback) {
   return ReadMapFile("/proc/" + std::to_string(pid) + "/maps", callback);
 }
 
+inline bool ReadProcessMaps(pid_t pid, const MapInfoParamsCallback& callback,
+                            std::string& mapsBuffer) {
+  return ReadMapFile("/proc/" + std::to_string(pid) + "/maps", callback, mapsBuffer);
+}
+
 inline bool ReadProcessMaps(pid_t pid, const MapInfoParamsCallback& callback) {
-  return ReadMapFile("/proc/" + std::to_string(pid) + "/maps", callback);
+  std::string content;
+  return ReadProcessMaps(pid, callback, content);
 }
 
 inline bool ReadProcessMaps(pid_t pid, std::vector<MapInfo>* maps) {
diff --git a/process.cpp b/process.cpp
index 92f58d9..884570d 100644
--- a/process.cpp
+++ b/process.cpp
@@ -31,19 +31,34 @@
 namespace android {
 namespace procinfo {
 
-bool GetProcessInfo(pid_t tid, ProcessInfo* process_info, std::string* error) {
-  char path[PATH_MAX];
-  snprintf(path, sizeof(path), "/proc/%d", tid);
+bool SetError(std::string* error, int errno_value, const char* fmt, ...) {
+  if (error == nullptr) return false;
 
-  unique_fd dirfd(open(path, O_DIRECTORY | O_RDONLY));
-  if (dirfd == -1) {
-    if (error != nullptr) {
-      *error = std::string("failed to open ") + path;
-    }
-    return false;
+  std::string result;
+  va_list ap;
+  va_start(ap, fmt);
+  android::base::StringAppendV(&result, fmt, ap);
+  va_end(ap);
+
+  if (errno_value != 0) {
+    result += ": ";
+    result += strerror(errno_value);
   }
 
-  return GetProcessInfoFromProcPidFd(dirfd.get(), process_info, error);
+  *error = result;
+  return false;
+}
+
+bool GetProcessInfo(pid_t tid, ProcessInfo* process_info, std::string* error) {
+  char path[32];
+  snprintf(path, sizeof(path), "/proc/%d", tid);
+
+  unique_fd dirfd(open(path, O_DIRECTORY | O_RDONLY | O_CLOEXEC));
+  if (dirfd == -1) {
+    return SetError(error, errno, "failed to open %s", path);
+  }
+
+  return GetProcessInfoFromProcPidFd(dirfd.get(), tid, process_info, error);
 }
 
 static ProcessState parse_state(char state) {
@@ -63,26 +78,18 @@
   }
 }
 
-bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info,
+bool GetProcessInfoFromProcPidFd(int fd, int pid, ProcessInfo* process_info,
                                  std::string* error /* can be nullptr */) {
   int status_fd = openat(fd, "status", O_RDONLY | O_CLOEXEC);
-
-  auto set_error = [&error](const char* err) {
-    if (error != nullptr) {
-      *error = err;
-    }
-  };
-
   if (status_fd == -1) {
-    set_error("failed to open status fd in GetProcessInfoFromProcPidFd");
-    return false;
+    return SetError(error, errno,
+                    "failed to open /proc/%d/status in GetProcessInfoFromProcPidFd", pid);
   }
 
-  std::unique_ptr<FILE, decltype(&fclose)> fp(fdopen(status_fd, "r"), fclose);
+  std::unique_ptr<FILE, decltype(&fclose)> fp(fdopen(status_fd, "re"), fclose);
   if (!fp) {
-    set_error("failed to open status file in GetProcessInfoFromProcPidFd");
     close(status_fd);
-    return false;
+    return SetError(error, errno, "failed to open FILE for /proc/%d/status in GetProcessInfoFromProcPidFd", pid);
   }
 
   int field_bitmap = 0;
@@ -126,19 +133,17 @@
 
   free(line);
   if (field_bitmap != finished_bitmap) {
-    set_error("failed to parse /proc/<pid>/status");
-    return false;
+    return SetError(error, 0, "failed to parse /proc/%d/status", pid);
   }
 
   unique_fd stat_fd(openat(fd, "stat", O_RDONLY | O_CLOEXEC));
   if (stat_fd == -1) {
-    set_error("failed to open /proc/<pid>/stat");
+    return SetError(error, errno, "failed to open /proc/%d/stat", pid);
   }
 
   std::string stat;
   if (!android::base::ReadFdToString(stat_fd, &stat)) {
-    set_error("failed to read /proc/<pid>/stat");
-    return false;
+    return SetError(error, errno, "failed to read /proc/%d/stat", pid);
   }
 
   // See man 5 proc. There's no reason comm can't contain ' ' or ')',
@@ -173,8 +178,7 @@
   unsigned long long start_time = 0;
   int rc = sscanf(end_of_comm + 2, pattern, &state, &ppid, &start_time);
   if (rc != 3) {
-    set_error("failed to parse /proc/<pid>/stat");
-    return false;
+    return SetError(error, 0, "failed to parse /proc/%d/stat", pid);
   }
 
   process_info->state = parse_state(state);
diff --git a/process_test.cpp b/process_test.cpp
index 0f25f92..a9d2f19 100644
--- a/process_test.cpp
+++ b/process_test.cpp
@@ -21,6 +21,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <algorithm>
 #include <chrono>
 #include <set>
 #include <thread>
@@ -56,7 +57,7 @@
   android::procinfo::ProcessInfo self;
   int fd = open(android::base::StringPrintf("/proc/%d", gettid()).c_str(), O_DIRECTORY | O_RDONLY);
   ASSERT_NE(-1, fd);
-  ASSERT_TRUE(android::procinfo::GetProcessInfoFromProcPidFd(fd, &self));
+  ASSERT_TRUE(android::procinfo::GetProcessInfoFromProcPidFd(fd, gettid(), &self));
 
   // Process name is capped at 15 bytes.
   ASSERT_EQ("libprocinfo_tes", self.name);
@@ -102,19 +103,22 @@
     _exit(0);
   }
 
-  // Give the child some time to get to the read.
-  std::this_thread::sleep_for(100ms);
 
+  // Give the child some time to get to the read.
   android::procinfo::ProcessInfo procinfo;
-  ASSERT_TRUE(android::procinfo::GetProcessInfo(forkpid, &procinfo));
+  for (int loop = 0; loop < 50 && procinfo.state != android::procinfo::kProcessStateSleeping; loop++) {
+   std::this_thread::sleep_for(100ms);
+   ASSERT_TRUE(android::procinfo::GetProcessInfo(forkpid, &procinfo));
+  }
   ASSERT_EQ(android::procinfo::kProcessStateSleeping, procinfo.state);
 
   ASSERT_EQ(0, kill(forkpid, SIGKILL));
 
   // Give the kernel some time to kill the child.
-  std::this_thread::sleep_for(100ms);
-
-  ASSERT_TRUE(android::procinfo::GetProcessInfo(forkpid, &procinfo));
+  for (int loop = 0; loop < 50 && procinfo.state != android::procinfo::kProcessStateZombie; loop++) {
+    std::this_thread::sleep_for(100ms);
+    ASSERT_TRUE(android::procinfo::GetProcessInfo(forkpid, &procinfo));
+  }
   ASSERT_EQ(android::procinfo::kProcessStateZombie, procinfo.state);
 
   ASSERT_EQ(forkpid, waitpid(forkpid, nullptr, 0));
@@ -170,29 +174,31 @@
 
   // failed to open status file error
   // No segfault if not given error string.
-  ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), &procinfo));
+  ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), 0, &procinfo));
   // Set error when given error string.
-  ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), &procinfo, &error));
-  ASSERT_EQ(error, "failed to open status fd in GetProcessInfoFromProcPidFd");
+  ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), 0, &procinfo, &error));
+  ASSERT_EQ(error, "failed to open /proc/0/status in GetProcessInfoFromProcPidFd: No such file or directory");
 
   // failed to parse status file error
   std::string status_file = std::string(tmp_dir.path) + "/status";
   ASSERT_TRUE(android::base::WriteStringToFile("invalid data", status_file));
-  ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), &procinfo));
-  ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), &procinfo, &error));
-  ASSERT_EQ(error, "failed to parse /proc/<pid>/status");
+  ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), 0, &procinfo));
+  ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), 0, &procinfo, &error));
+  ASSERT_EQ(error, "failed to parse /proc/0/status");
 
-  // failed to read stat file error
+  // Give the "/status" file valid contents.
   ASSERT_TRUE(android::base::WriteStringToFile(
       "Name:\tsh\nTgid:\t0\nPid:\t0\nTracerPid:\t0\nUid:\t0\nGid:\t0\n", status_file));
-  ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), &procinfo));
-  ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), &procinfo, &error));
-  ASSERT_EQ(error, "failed to read /proc/<pid>/stat");
+
+  // failed to open stat file error
+  ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), 0, &procinfo));
+  ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), 0, &procinfo, &error));
+  ASSERT_EQ(error, "failed to open /proc/0/stat: No such file or directory");
 
   // failed to parse stat file error
   std::string stat_file = std::string(tmp_dir.path) + "/stat";
   ASSERT_TRUE(android::base::WriteStringToFile("2027 (sh) invalid data", stat_file));
-  ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), &procinfo));
-  ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), &procinfo, &error));
-  ASSERT_EQ(error, "failed to parse /proc/<pid>/stat");
+  ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), 0, &procinfo));
+  ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), 0, &procinfo, &error));
+  ASSERT_EQ(error, "failed to parse /proc/0/stat");
 }