Merge changes I5c6bf2a5,I20a337bb
am: 7f81b2af61
Change-Id: I5388b048cdcc41d374b1d58476def364409b72b2
This commit is contained in:
commit
14e36421db
5 changed files with 86 additions and 1 deletions
|
|
@ -274,6 +274,7 @@ cc_binary {
|
||||||
"libbase",
|
"libbase",
|
||||||
"libdebuggerd_client",
|
"libdebuggerd_client",
|
||||||
"liblog",
|
"liblog",
|
||||||
|
"libprocinfo",
|
||||||
"libselinux",
|
"libselinux",
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
#include <android-base/parseint.h>
|
#include <android-base/parseint.h>
|
||||||
#include <android-base/unique_fd.h>
|
#include <android-base/unique_fd.h>
|
||||||
#include <debuggerd/client.h>
|
#include <debuggerd/client.h>
|
||||||
|
#include <procinfo/process.h>
|
||||||
#include <selinux/selinux.h>
|
#include <selinux/selinux.h>
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
|
@ -66,6 +67,24 @@ int main(int argc, char* argv[]) {
|
||||||
usage(1);
|
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;
|
unique_fd piperead, pipewrite;
|
||||||
if (!Pipe(&piperead, &pipewrite)) {
|
if (!Pipe(&piperead, &pipewrite)) {
|
||||||
err(1, "failed to create pipe");
|
err(1, "failed to create pipe");
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,18 @@ namespace procinfo {
|
||||||
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
|
|
||||||
|
enum ProcessState {
|
||||||
|
kProcessStateUnknown,
|
||||||
|
kProcessStateRunning,
|
||||||
|
kProcessStateSleeping,
|
||||||
|
kProcessStateUninterruptibleWait,
|
||||||
|
kProcessStateStopped,
|
||||||
|
kProcessStateZombie,
|
||||||
|
};
|
||||||
|
|
||||||
struct ProcessInfo {
|
struct ProcessInfo {
|
||||||
std::string name;
|
std::string name;
|
||||||
|
ProcessState state;
|
||||||
pid_t tid;
|
pid_t tid;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
pid_t ppid;
|
pid_t ppid;
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,24 @@ bool GetProcessInfo(pid_t tid, ProcessInfo* process_info) {
|
||||||
return GetProcessInfoFromProcPidFd(dirfd.get(), process_info);
|
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) {
|
bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info) {
|
||||||
int status_fd = openat(fd, "status", O_RDONLY | O_CLOEXEC);
|
int status_fd = openat(fd, "status", O_RDONLY | O_CLOEXEC);
|
||||||
|
|
||||||
|
|
@ -60,7 +78,7 @@ bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int field_bitmap = 0;
|
int field_bitmap = 0;
|
||||||
static constexpr int finished_bitmap = 127;
|
static constexpr int finished_bitmap = 255;
|
||||||
char* line = nullptr;
|
char* line = nullptr;
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
|
|
||||||
|
|
@ -98,6 +116,9 @@ bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info) {
|
||||||
} else if (header == "Gid:") {
|
} else if (header == "Gid:") {
|
||||||
process_info->gid = atoi(tab + 1);
|
process_info->gid = atoi(tab + 1);
|
||||||
field_bitmap |= 64;
|
field_bitmap |= 64;
|
||||||
|
} else if (header == "State:") {
|
||||||
|
process_info->state = parse_state(tab + 1);
|
||||||
|
field_bitmap |= 128;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
@ -29,6 +30,8 @@
|
||||||
|
|
||||||
#include <android-base/stringprintf.h>
|
#include <android-base/stringprintf.h>
|
||||||
|
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
#if !defined(__BIONIC__)
|
#if !defined(__BIONIC__)
|
||||||
#include <syscall.h>
|
#include <syscall.h>
|
||||||
static pid_t gettid() {
|
static pid_t gettid() {
|
||||||
|
|
@ -82,3 +85,34 @@ TEST(process_info, process_tids_smoke) {
|
||||||
}
|
}
|
||||||
}).join();
|
}).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));
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue