summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Gao2016-10-28 17:23:25 -0500
committerJosh Gao2016-11-14 15:42:18 -0600
commit911d729c8a01fbc052a8e15322bad5413a1138a9 (patch)
treed3e2f90c4643de9a2cad98d93c91bb0206990a27 /libprocinfo
parentf77d8b04528775e7a2e22255bb9a46b0e1df8ef1 (diff)
downloadplatform-system-core-911d729c8a01fbc052a8e15322bad5413a1138a9.tar.gz
platform-system-core-911d729c8a01fbc052a8e15322bad5413a1138a9.tar.xz
platform-system-core-911d729c8a01fbc052a8e15322bad5413a1138a9.zip
libprocinfo: introduce.
Add a new library for parsing /proc files. Start with helpers for parsing /proc/<pid>/status and /proc/<pid>/task. Bug: http://b/30705528 Test: libprocinfo_test32/64 on host/bullhead Change-Id: I5757514c0aede8a9d75834b55aae42a5cf762b95
Diffstat (limited to 'libprocinfo')
-rw-r--r--libprocinfo/.clang-format14
-rw-r--r--libprocinfo/Android.bp73
-rw-r--r--libprocinfo/include/procinfo/process.h106
-rw-r--r--libprocinfo/process.cpp109
-rw-r--r--libprocinfo/process_test.cpp84
5 files changed, 386 insertions, 0 deletions
diff --git a/libprocinfo/.clang-format b/libprocinfo/.clang-format
new file mode 100644
index 000000000..b8c642840
--- /dev/null
+++ b/libprocinfo/.clang-format
@@ -0,0 +1,14 @@
1BasedOnStyle: Google
2AllowShortBlocksOnASingleLine: false
3AllowShortFunctionsOnASingleLine: false
4
5ColumnLimit: 100
6CommentPragmas: NOLINT:.*
7DerivePointerAlignment: false
8IndentWidth: 2
9PointerAlignment: Left
10TabWidth: 2
11UseTab: Never
12PenaltyExcessCharacter: 32
13
14Cpp11BracedListStyle: false
diff --git a/libprocinfo/Android.bp b/libprocinfo/Android.bp
new file mode 100644
index 000000000..8e17f1b1b
--- /dev/null
+++ b/libprocinfo/Android.bp
@@ -0,0 +1,73 @@
1//
2// Copyright (C) 2015 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17libprocinfo_cppflags = [
18 "-Wall",
19 "-Wextra",
20 "-Werror",
21]
22
23cc_library {
24 name: "libprocinfo",
25 host_supported: true,
26 srcs: [
27 "process.cpp",
28 ],
29 cppflags: libprocinfo_cppflags,
30
31 local_include_dirs: ["include"],
32 export_include_dirs: ["include"],
33 shared_libs: ["libbase"],
34 target: {
35 darwin: {
36 enabled: false,
37 },
38 windows: {
39 enabled: false,
40 },
41 },
42}
43
44// Tests
45// ------------------------------------------------------------------------------
46cc_test {
47 name: "libprocinfo_test",
48 host_supported: true,
49 srcs: [
50 "process_test.cpp",
51 ],
52 target: {
53 darwin: {
54 enabled: false,
55 },
56 windows: {
57 enabled: false,
58 },
59 },
60
61 cppflags: libprocinfo_cppflags,
62 shared_libs: ["libbase", "libprocinfo"],
63
64 compile_multilib: "both",
65 multilib: {
66 lib32: {
67 suffix: "32",
68 },
69 lib64: {
70 suffix: "64",
71 },
72 },
73}
diff --git a/libprocinfo/include/procinfo/process.h b/libprocinfo/include/procinfo/process.h
new file mode 100644
index 000000000..fb140ff3d
--- /dev/null
+++ b/libprocinfo/include/procinfo/process.h
@@ -0,0 +1,106 @@
1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#pragma once
18
19#include <dirent.h>
20#include <fcntl.h>
21#include <stdlib.h>
22#include <sys/types.h>
23#include <unistd.h>
24
25#include <memory>
26#include <string>
27#include <type_traits>
28
29#include <android-base/logging.h>
30#include <android-base/parseint.h>
31#include <android-base/unique_fd.h>
32
33namespace android {
34namespace procinfo {
35
36#if defined(__linux__)
37
38struct ProcessInfo {
39 std::string name;
40 pid_t tid;
41 pid_t pid;
42 pid_t ppid;
43 pid_t tracer;
44 uid_t uid;
45 uid_t gid;
46};
47
48// Parse the contents of /proc/<tid>/status into |process_info|.
49bool GetProcessInfo(pid_t tid, ProcessInfo* process_info);
50
51// Parse the contents of <fd>/status into |process_info|.
52// |fd| should be an fd pointing at a /proc/<pid> directory.
53bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info);
54
55// Fetch the list of threads from a given process's /proc/<pid> directory.
56// |fd| should be an fd pointing at a /proc/<pid> directory.
57template <typename Collection>
58auto GetProcessTidsFromProcPidFd(int fd, Collection* out) ->
59 typename std::enable_if<sizeof(typename Collection::value_type) >= sizeof(pid_t), bool>::type {
60 out->clear();
61
62 int task_fd = openat(fd, "task", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
63 std::unique_ptr<DIR, int (*)(DIR*)> dir(fdopendir(task_fd), closedir);
64 if (!dir) {
65 PLOG(ERROR) << "failed to open task directory";
66 return false;
67 }
68
69 struct dirent* dent;
70 while ((dent = readdir(dir.get()))) {
71 if (strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0) {
72 pid_t tid;
73 if (!android::base::ParseInt(dent->d_name, &tid, 1, std::numeric_limits<pid_t>::max())) {
74 LOG(ERROR) << "failed to parse task id: " << dent->d_name;
75 return false;
76 }
77
78 out->insert(out->end(), tid);
79 }
80 }
81
82 return true;
83}
84
85template <typename Collection>
86auto GetProcessTids(pid_t pid, Collection* out) ->
87 typename std::enable_if<sizeof(typename Collection::value_type) >= sizeof(pid_t), bool>::type {
88 char task_path[PATH_MAX];
89 if (snprintf(task_path, PATH_MAX, "/proc/%d", pid) >= PATH_MAX) {
90 LOG(ERROR) << "task path overflow (pid = " << pid << ")";
91 return false;
92 }
93
94 android::base::unique_fd fd(open(task_path, O_DIRECTORY | O_RDONLY | O_CLOEXEC));
95 if (fd == -1) {
96 PLOG(ERROR) << "failed to open " << task_path;
97 return false;
98 }
99
100 return GetProcessTidsFromProcPidFd(fd.get(), out);
101}
102
103#endif
104
105} /* namespace procinfo */
106} /* namespace android */
diff --git a/libprocinfo/process.cpp b/libprocinfo/process.cpp
new file mode 100644
index 000000000..c513e16f5
--- /dev/null
+++ b/libprocinfo/process.cpp
@@ -0,0 +1,109 @@
1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <procinfo/process.h>
18
19#include <fcntl.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <unistd.h>
24
25#include <string>
26
27#include <android-base/unique_fd.h>
28
29using android::base::unique_fd;
30
31namespace android {
32namespace procinfo {
33
34bool GetProcessInfo(pid_t tid, ProcessInfo* process_info) {
35 char path[PATH_MAX];
36 snprintf(path, sizeof(path), "/proc/%d", tid);
37
38 unique_fd dirfd(open(path, O_DIRECTORY | O_RDONLY));
39 if (dirfd == -1) {
40 PLOG(ERROR) << "failed to open " << path;
41 return false;
42 }
43
44 return GetProcessInfoFromProcPidFd(dirfd.get(), process_info);
45}
46
47bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info) {
48 int status_fd = openat(fd, "status", O_RDONLY | O_CLOEXEC);
49
50 if (status_fd == -1) {
51 PLOG(ERROR) << "failed to open status fd in GetProcessInfoFromProcPidFd";
52 return false;
53 }
54
55 std::unique_ptr<FILE, decltype(&fclose)> fp(fdopen(status_fd, "r"), fclose);
56 if (!fp) {
57 PLOG(ERROR) << "failed to open status file in GetProcessInfoFromProcPidFd";
58 close(status_fd);
59 return false;
60 }
61
62 int field_bitmap = 0;
63 static constexpr int finished_bitmap = 127;
64 char* line = nullptr;
65 size_t len = 0;
66
67 while (getline(&line, &len, fp.get()) != -1 && field_bitmap != finished_bitmap) {
68 char* tab = strchr(line, '\t');
69 if (tab == nullptr) {
70 continue;
71 }
72
73 size_t header_len = tab - line;
74 std::string header = std::string(line, header_len);
75 if (header == "Name:") {
76 std::string name = line + header_len + 1;
77
78 // line includes the trailing newline.
79 name.pop_back();
80 process_info->name = std::move(name);
81
82 field_bitmap |= 1;
83 } else if (header == "Pid:") {
84 process_info->tid = atoi(tab + 1);
85 field_bitmap |= 2;
86 } else if (header == "Tgid:") {
87 process_info->pid = atoi(tab + 1);
88 field_bitmap |= 4;
89 } else if (header == "PPid:") {
90 process_info->ppid = atoi(tab + 1);
91 field_bitmap |= 8;
92 } else if (header == "TracerPid:") {
93 process_info->tracer = atoi(tab + 1);
94 field_bitmap |= 16;
95 } else if (header == "Uid:") {
96 process_info->uid = atoi(tab + 1);
97 field_bitmap |= 32;
98 } else if (header == "Gid:") {
99 process_info->gid = atoi(tab + 1);
100 field_bitmap |= 64;
101 }
102 }
103
104 free(line);
105 return field_bitmap == finished_bitmap;
106}
107
108} /* namespace procinfo */
109} /* namespace android */
diff --git a/libprocinfo/process_test.cpp b/libprocinfo/process_test.cpp
new file mode 100644
index 000000000..5ffd2365b
--- /dev/null
+++ b/libprocinfo/process_test.cpp
@@ -0,0 +1,84 @@
1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <procinfo/process.h>
18
19#include <fcntl.h>
20#include <stdlib.h>
21#include <sys/types.h>
22#include <unistd.h>
23
24#include <set>
25#include <thread>
26#include <vector>
27
28#include <gtest/gtest.h>
29
30#include <android-base/stringprintf.h>
31
32#if !defined(__BIONIC__)
33#include <syscall.h>
34static pid_t gettid() {
35 return syscall(__NR_gettid);
36}
37#endif
38
39TEST(process_info, process_info_smoke) {
40 android::procinfo::ProcessInfo self;
41 ASSERT_TRUE(android::procinfo::GetProcessInfo(gettid(), &self));
42 ASSERT_EQ(gettid(), self.tid);
43 ASSERT_EQ(getpid(), self.pid);
44 ASSERT_EQ(getppid(), self.ppid);
45 ASSERT_EQ(getuid(), self.uid);
46 ASSERT_EQ(getgid(), self.gid);
47}
48
49TEST(process_info, process_info_proc_pid_fd_smoke) {
50 android::procinfo::ProcessInfo self;
51 int fd = open(android::base::StringPrintf("/proc/%d", gettid()).c_str(), O_DIRECTORY | O_RDONLY);
52 ASSERT_NE(-1, fd);
53 ASSERT_TRUE(android::procinfo::GetProcessInfoFromProcPidFd(fd, &self));
54
55 // Process name is capped at 15 bytes.
56 ASSERT_EQ("libprocinfo_tes", self.name);
57 ASSERT_EQ(gettid(), self.tid);
58 ASSERT_EQ(getpid(), self.pid);
59 ASSERT_EQ(getppid(), self.ppid);
60 ASSERT_EQ(getuid(), self.uid);
61 ASSERT_EQ(getgid(), self.gid);
62 close(fd);
63}
64
65TEST(process_info, process_tids_smoke) {
66 pid_t main_tid = gettid();
67 std::thread([main_tid]() {
68 pid_t thread_tid = gettid();
69
70 {
71 std::vector<pid_t> vec;
72 ASSERT_TRUE(android::procinfo::GetProcessTids(getpid(), &vec));
73 ASSERT_EQ(1, std::count(vec.begin(), vec.end(), main_tid));
74 ASSERT_EQ(1, std::count(vec.begin(), vec.end(), thread_tid));
75 }
76
77 {
78 std::set<pid_t> set;
79 ASSERT_TRUE(android::procinfo::GetProcessTids(getpid(), &set));
80 ASSERT_EQ(1, std::count(set.begin(), set.end(), main_tid));
81 ASSERT_EQ(1, std::count(set.begin(), set.end(), thread_tid));
82 }
83 }).join();
84}