blob: 0f25f924dfaeb134eacdffbdbb3167c3c708aca1 [file] [log] [blame]
Josh Gao788a35d2016-10-28 15:23:25 -07001/*
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
Josh Gao8a1b53c2017-06-27 14:06:19 -070024#include <chrono>
Josh Gao788a35d2016-10-28 15:23:25 -070025#include <set>
26#include <thread>
27#include <vector>
28
29#include <gtest/gtest.h>
30
Yabin Cui3dbe8232021-05-18 15:36:53 -070031#include <android-base/file.h>
Josh Gao67887fe2021-03-01 23:02:54 -080032#include <android-base/logging.h>
Josh Gao788a35d2016-10-28 15:23:25 -070033#include <android-base/stringprintf.h>
Yabin Cui3dbe8232021-05-18 15:36:53 -070034#include <android-base/unique_fd.h>
Josh Gao788a35d2016-10-28 15:23:25 -070035
Josh Gao8a1b53c2017-06-27 14:06:19 -070036using namespace std::chrono_literals;
37
Colin Crossa4a14a32022-02-02 16:39:44 -080038#if defined(__GLIBC__)
Josh Gao788a35d2016-10-28 15:23:25 -070039#include <syscall.h>
40static pid_t gettid() {
41 return syscall(__NR_gettid);
42}
43#endif
44
45TEST(process_info, process_info_smoke) {
46 android::procinfo::ProcessInfo self;
47 ASSERT_TRUE(android::procinfo::GetProcessInfo(gettid(), &self));
48 ASSERT_EQ(gettid(), self.tid);
49 ASSERT_EQ(getpid(), self.pid);
50 ASSERT_EQ(getppid(), self.ppid);
51 ASSERT_EQ(getuid(), self.uid);
52 ASSERT_EQ(getgid(), self.gid);
53}
54
55TEST(process_info, process_info_proc_pid_fd_smoke) {
56 android::procinfo::ProcessInfo self;
57 int fd = open(android::base::StringPrintf("/proc/%d", gettid()).c_str(), O_DIRECTORY | O_RDONLY);
58 ASSERT_NE(-1, fd);
59 ASSERT_TRUE(android::procinfo::GetProcessInfoFromProcPidFd(fd, &self));
60
61 // Process name is capped at 15 bytes.
62 ASSERT_EQ("libprocinfo_tes", self.name);
63 ASSERT_EQ(gettid(), self.tid);
64 ASSERT_EQ(getpid(), self.pid);
65 ASSERT_EQ(getppid(), self.ppid);
66 ASSERT_EQ(getuid(), self.uid);
67 ASSERT_EQ(getgid(), self.gid);
68 close(fd);
69}
70
71TEST(process_info, process_tids_smoke) {
72 pid_t main_tid = gettid();
73 std::thread([main_tid]() {
74 pid_t thread_tid = gettid();
75
76 {
77 std::vector<pid_t> vec;
78 ASSERT_TRUE(android::procinfo::GetProcessTids(getpid(), &vec));
79 ASSERT_EQ(1, std::count(vec.begin(), vec.end(), main_tid));
80 ASSERT_EQ(1, std::count(vec.begin(), vec.end(), thread_tid));
81 }
82
83 {
84 std::set<pid_t> set;
85 ASSERT_TRUE(android::procinfo::GetProcessTids(getpid(), &set));
86 ASSERT_EQ(1, std::count(set.begin(), set.end(), main_tid));
87 ASSERT_EQ(1, std::count(set.begin(), set.end(), thread_tid));
88 }
89 }).join();
90}
Josh Gao8a1b53c2017-06-27 14:06:19 -070091
92TEST(process_info, process_state) {
93 int pipefd[2];
94 ASSERT_EQ(0, pipe2(pipefd, O_CLOEXEC));
95 pid_t forkpid = fork();
96
97 ASSERT_NE(-1, forkpid);
98 if (forkpid == 0) {
99 close(pipefd[1]);
100 char buf;
101 TEMP_FAILURE_RETRY(read(pipefd[0], &buf, 1));
102 _exit(0);
103 }
104
105 // Give the child some time to get to the read.
106 std::this_thread::sleep_for(100ms);
107
108 android::procinfo::ProcessInfo procinfo;
109 ASSERT_TRUE(android::procinfo::GetProcessInfo(forkpid, &procinfo));
110 ASSERT_EQ(android::procinfo::kProcessStateSleeping, procinfo.state);
111
112 ASSERT_EQ(0, kill(forkpid, SIGKILL));
113
114 // Give the kernel some time to kill the child.
115 std::this_thread::sleep_for(100ms);
116
117 ASSERT_TRUE(android::procinfo::GetProcessInfo(forkpid, &procinfo));
118 ASSERT_EQ(android::procinfo::kProcessStateZombie, procinfo.state);
119
120 ASSERT_EQ(forkpid, waitpid(forkpid, nullptr, 0));
121}
Josh Gao67887fe2021-03-01 23:02:54 -0800122
123static uint64_t read_uptime_secs() {
124 std::string uptime;
125 if (!android::base::ReadFileToString("/proc/uptime", &uptime)) {
126 PLOG(FATAL) << "failed to read /proc/uptime";
127 }
128 return strtoll(uptime.c_str(), nullptr, 10);
129}
130
131TEST(process_info, process_start_time) {
132 uint64_t start = read_uptime_secs();
133 int pipefd[2];
134 ASSERT_EQ(0, pipe2(pipefd, O_CLOEXEC));
135
136 std::this_thread::sleep_for(1000ms);
137
138 pid_t forkpid = fork();
139
140 ASSERT_NE(-1, forkpid);
141 if (forkpid == 0) {
142 close(pipefd[1]);
143 char buf;
144 TEMP_FAILURE_RETRY(read(pipefd[0], &buf, 1));
145 _exit(0);
146 }
147
148 std::this_thread::sleep_for(1000ms);
149
150 uint64_t end = read_uptime_secs();
151
152 android::procinfo::ProcessInfo procinfo;
153 ASSERT_TRUE(android::procinfo::GetProcessInfo(forkpid, &procinfo));
154
155 // starttime is measured in clock ticks: uptime is in seconds:
156 uint64_t process_start = procinfo.starttime / sysconf(_SC_CLK_TCK);
157 ASSERT_LE(start, process_start);
158 ASSERT_LE(process_start, end);
159
160 ASSERT_EQ(0, kill(forkpid, SIGKILL));
161 ASSERT_EQ(forkpid, waitpid(forkpid, nullptr, 0));
162}
Yabin Cui3dbe8232021-05-18 15:36:53 -0700163
164TEST(process_info, GetProcessInfoFromProcPidFd_set_error) {
165 TemporaryDir tmp_dir;
166
167 android::base::unique_fd dirfd(open(tmp_dir.path, O_DIRECTORY | O_RDONLY));
168 android::procinfo::ProcessInfo procinfo;
169 std::string error;
170
171 // failed to open status file error
172 // No segfault if not given error string.
173 ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), &procinfo));
174 // Set error when given error string.
175 ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), &procinfo, &error));
176 ASSERT_EQ(error, "failed to open status fd in GetProcessInfoFromProcPidFd");
177
178 // failed to parse status file error
179 std::string status_file = std::string(tmp_dir.path) + "/status";
180 ASSERT_TRUE(android::base::WriteStringToFile("invalid data", status_file));
181 ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), &procinfo));
182 ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), &procinfo, &error));
183 ASSERT_EQ(error, "failed to parse /proc/<pid>/status");
184
185 // failed to read stat file error
186 ASSERT_TRUE(android::base::WriteStringToFile(
187 "Name:\tsh\nTgid:\t0\nPid:\t0\nTracerPid:\t0\nUid:\t0\nGid:\t0\n", status_file));
188 ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), &procinfo));
189 ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), &procinfo, &error));
190 ASSERT_EQ(error, "failed to read /proc/<pid>/stat");
191
192 // failed to parse stat file error
193 std::string stat_file = std::string(tmp_dir.path) + "/stat";
194 ASSERT_TRUE(android::base::WriteStringToFile("2027 (sh) invalid data", stat_file));
195 ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), &procinfo));
196 ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), &procinfo, &error));
197 ASSERT_EQ(error, "failed to parse /proc/<pid>/stat");
198}