Merge changes I5c6bf2a5,I20a337bb am: 7f81b2af61 am: 14e36421db am: 877708fcf1
am: 639dcaddeb
Change-Id: I8f7c84eb968962bef509fd3df86a2e4ecf3fc210
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 5565cfd..f993820 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -274,6 +274,7 @@
"libbase",
"libdebuggerd_client",
"liblog",
+ "libprocinfo",
"libselinux",
],
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 6298ace..0cc5f69 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -27,6 +27,7 @@
#include <android-base/parseint.h>
#include <android-base/unique_fd.h>
#include <debuggerd/client.h>
+#include <procinfo/process.h>
#include <selinux/selinux.h>
#include "util.h"
@@ -66,6 +67,24 @@
usage(1);
}
+ if (getuid() != 0) {
+ errx(1, "root is required");
+ }
+
+ // Check to see if the process exists and that we can actually send a signal to it.
+ android::procinfo::ProcessInfo proc_info;
+ if (!android::procinfo::GetProcessInfo(pid, &proc_info)) {
+ err(1, "failed to fetch info for process %d", pid);
+ }
+
+ if (proc_info.state == android::procinfo::kProcessStateZombie) {
+ errx(1, "process %d is a zombie", pid);
+ }
+
+ if (kill(pid, 0) != 0) {
+ err(1, "cannot send signal to process %d", pid);
+ }
+
unique_fd piperead, pipewrite;
if (!Pipe(&piperead, &pipewrite)) {
err(1, "failed to create pipe");
diff --git a/libprocinfo/include/procinfo/process.h b/libprocinfo/include/procinfo/process.h
index fb140ff..db56fc1 100644
--- a/libprocinfo/include/procinfo/process.h
+++ b/libprocinfo/include/procinfo/process.h
@@ -35,8 +35,18 @@
#if defined(__linux__)
+enum ProcessState {
+ kProcessStateUnknown,
+ kProcessStateRunning,
+ kProcessStateSleeping,
+ kProcessStateUninterruptibleWait,
+ kProcessStateStopped,
+ kProcessStateZombie,
+};
+
struct ProcessInfo {
std::string name;
+ ProcessState state;
pid_t tid;
pid_t pid;
pid_t ppid;
diff --git a/libprocinfo/process.cpp b/libprocinfo/process.cpp
index c513e16..6e5be6e 100644
--- a/libprocinfo/process.cpp
+++ b/libprocinfo/process.cpp
@@ -44,6 +44,24 @@
return GetProcessInfoFromProcPidFd(dirfd.get(), process_info);
}
+static ProcessState parse_state(const char* state) {
+ switch (*state) {
+ case 'R':
+ return kProcessStateRunning;
+ case 'S':
+ return kProcessStateSleeping;
+ case 'D':
+ return kProcessStateUninterruptibleWait;
+ case 'T':
+ return kProcessStateStopped;
+ case 'Z':
+ return kProcessStateZombie;
+ default:
+ LOG(ERROR) << "unknown process state: " << *state;
+ return kProcessStateUnknown;
+ }
+}
+
bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info) {
int status_fd = openat(fd, "status", O_RDONLY | O_CLOEXEC);
@@ -60,7 +78,7 @@
}
int field_bitmap = 0;
- static constexpr int finished_bitmap = 127;
+ static constexpr int finished_bitmap = 255;
char* line = nullptr;
size_t len = 0;
@@ -98,6 +116,9 @@
} else if (header == "Gid:") {
process_info->gid = atoi(tab + 1);
field_bitmap |= 64;
+ } else if (header == "State:") {
+ process_info->state = parse_state(tab + 1);
+ field_bitmap |= 128;
}
}
diff --git a/libprocinfo/process_test.cpp b/libprocinfo/process_test.cpp
index 5ffd236..9da9278 100644
--- a/libprocinfo/process_test.cpp
+++ b/libprocinfo/process_test.cpp
@@ -21,6 +21,7 @@
#include <sys/types.h>
#include <unistd.h>
+#include <chrono>
#include <set>
#include <thread>
#include <vector>
@@ -29,6 +30,8 @@
#include <android-base/stringprintf.h>
+using namespace std::chrono_literals;
+
#if !defined(__BIONIC__)
#include <syscall.h>
static pid_t gettid() {
@@ -82,3 +85,34 @@
}
}).join();
}
+
+TEST(process_info, process_state) {
+ int pipefd[2];
+ ASSERT_EQ(0, pipe2(pipefd, O_CLOEXEC));
+ pid_t forkpid = fork();
+
+ ASSERT_NE(-1, forkpid);
+ if (forkpid == 0) {
+ close(pipefd[1]);
+ char buf;
+ TEMP_FAILURE_RETRY(read(pipefd[0], &buf, 1));
+ _exit(0);
+ }
+
+ // Give the child some time to get to the read.
+ std::this_thread::sleep_for(100ms);
+
+ android::procinfo::ProcessInfo procinfo;
+ 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));
+ ASSERT_EQ(android::procinfo::kProcessStateZombie, procinfo.state);
+
+ ASSERT_EQ(forkpid, waitpid(forkpid, nullptr, 0));
+}