1*e7c5e80fSMitch Phillips /*
2*e7c5e80fSMitch Phillips * Copyright (C) 2016 The Android Open Source Project
3*e7c5e80fSMitch Phillips *
4*e7c5e80fSMitch Phillips * Licensed under the Apache License, Version 2.0 (the "License");
5*e7c5e80fSMitch Phillips * you may not use this file except in compliance with the License.
6*e7c5e80fSMitch Phillips * You may obtain a copy of the License at
7*e7c5e80fSMitch Phillips *
8*e7c5e80fSMitch Phillips * http://www.apache.org/licenses/LICENSE-2.0
9*e7c5e80fSMitch Phillips *
10*e7c5e80fSMitch Phillips * Unless required by applicable law or agreed to in writing, software
11*e7c5e80fSMitch Phillips * distributed under the License is distributed on an "AS IS" BASIS,
12*e7c5e80fSMitch Phillips * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*e7c5e80fSMitch Phillips * See the License for the specific language governing permissions and
14*e7c5e80fSMitch Phillips * limitations under the License.
15*e7c5e80fSMitch Phillips */
16*e7c5e80fSMitch Phillips
17*e7c5e80fSMitch Phillips #include <procinfo/process.h>
18*e7c5e80fSMitch Phillips
19*e7c5e80fSMitch Phillips #include <fcntl.h>
20*e7c5e80fSMitch Phillips #include <stdlib.h>
21*e7c5e80fSMitch Phillips #include <sys/types.h>
22*e7c5e80fSMitch Phillips #include <unistd.h>
23*e7c5e80fSMitch Phillips
24*e7c5e80fSMitch Phillips #include <algorithm>
25*e7c5e80fSMitch Phillips #include <chrono>
26*e7c5e80fSMitch Phillips #include <set>
27*e7c5e80fSMitch Phillips #include <thread>
28*e7c5e80fSMitch Phillips #include <vector>
29*e7c5e80fSMitch Phillips
30*e7c5e80fSMitch Phillips #include <gtest/gtest.h>
31*e7c5e80fSMitch Phillips
32*e7c5e80fSMitch Phillips #include <android-base/file.h>
33*e7c5e80fSMitch Phillips #include <android-base/logging.h>
34*e7c5e80fSMitch Phillips #include <android-base/stringprintf.h>
35*e7c5e80fSMitch Phillips #include <android-base/unique_fd.h>
36*e7c5e80fSMitch Phillips
37*e7c5e80fSMitch Phillips using namespace std::chrono_literals;
38*e7c5e80fSMitch Phillips
39*e7c5e80fSMitch Phillips #if defined(__GLIBC__)
40*e7c5e80fSMitch Phillips #include <syscall.h>
gettid()41*e7c5e80fSMitch Phillips static pid_t gettid() {
42*e7c5e80fSMitch Phillips return syscall(__NR_gettid);
43*e7c5e80fSMitch Phillips }
44*e7c5e80fSMitch Phillips #endif
45*e7c5e80fSMitch Phillips
TEST(process_info,process_info_smoke)46*e7c5e80fSMitch Phillips TEST(process_info, process_info_smoke) {
47*e7c5e80fSMitch Phillips android::procinfo::ProcessInfo self;
48*e7c5e80fSMitch Phillips ASSERT_TRUE(android::procinfo::GetProcessInfo(gettid(), &self));
49*e7c5e80fSMitch Phillips ASSERT_EQ(gettid(), self.tid);
50*e7c5e80fSMitch Phillips ASSERT_EQ(getpid(), self.pid);
51*e7c5e80fSMitch Phillips ASSERT_EQ(getppid(), self.ppid);
52*e7c5e80fSMitch Phillips ASSERT_EQ(getuid(), self.uid);
53*e7c5e80fSMitch Phillips ASSERT_EQ(getgid(), self.gid);
54*e7c5e80fSMitch Phillips }
55*e7c5e80fSMitch Phillips
TEST(process_info,process_info_proc_pid_fd_smoke)56*e7c5e80fSMitch Phillips TEST(process_info, process_info_proc_pid_fd_smoke) {
57*e7c5e80fSMitch Phillips android::procinfo::ProcessInfo self;
58*e7c5e80fSMitch Phillips int fd = open(android::base::StringPrintf("/proc/%d", gettid()).c_str(), O_DIRECTORY | O_RDONLY);
59*e7c5e80fSMitch Phillips ASSERT_NE(-1, fd);
60*e7c5e80fSMitch Phillips ASSERT_TRUE(android::procinfo::GetProcessInfoFromProcPidFd(fd, gettid(), &self));
61*e7c5e80fSMitch Phillips
62*e7c5e80fSMitch Phillips // Process name is capped at 15 bytes.
63*e7c5e80fSMitch Phillips ASSERT_EQ("libprocinfo_tes", self.name);
64*e7c5e80fSMitch Phillips ASSERT_EQ(gettid(), self.tid);
65*e7c5e80fSMitch Phillips ASSERT_EQ(getpid(), self.pid);
66*e7c5e80fSMitch Phillips ASSERT_EQ(getppid(), self.ppid);
67*e7c5e80fSMitch Phillips ASSERT_EQ(getuid(), self.uid);
68*e7c5e80fSMitch Phillips ASSERT_EQ(getgid(), self.gid);
69*e7c5e80fSMitch Phillips close(fd);
70*e7c5e80fSMitch Phillips }
71*e7c5e80fSMitch Phillips
TEST(process_info,process_tids_smoke)72*e7c5e80fSMitch Phillips TEST(process_info, process_tids_smoke) {
73*e7c5e80fSMitch Phillips pid_t main_tid = gettid();
74*e7c5e80fSMitch Phillips std::thread([main_tid]() {
75*e7c5e80fSMitch Phillips pid_t thread_tid = gettid();
76*e7c5e80fSMitch Phillips
77*e7c5e80fSMitch Phillips {
78*e7c5e80fSMitch Phillips std::vector<pid_t> vec;
79*e7c5e80fSMitch Phillips ASSERT_TRUE(android::procinfo::GetProcessTids(getpid(), &vec));
80*e7c5e80fSMitch Phillips ASSERT_EQ(1, std::count(vec.begin(), vec.end(), main_tid));
81*e7c5e80fSMitch Phillips ASSERT_EQ(1, std::count(vec.begin(), vec.end(), thread_tid));
82*e7c5e80fSMitch Phillips }
83*e7c5e80fSMitch Phillips
84*e7c5e80fSMitch Phillips {
85*e7c5e80fSMitch Phillips std::set<pid_t> set;
86*e7c5e80fSMitch Phillips ASSERT_TRUE(android::procinfo::GetProcessTids(getpid(), &set));
87*e7c5e80fSMitch Phillips ASSERT_EQ(1, std::count(set.begin(), set.end(), main_tid));
88*e7c5e80fSMitch Phillips ASSERT_EQ(1, std::count(set.begin(), set.end(), thread_tid));
89*e7c5e80fSMitch Phillips }
90*e7c5e80fSMitch Phillips }).join();
91*e7c5e80fSMitch Phillips }
92*e7c5e80fSMitch Phillips
TEST(process_info,process_state)93*e7c5e80fSMitch Phillips TEST(process_info, process_state) {
94*e7c5e80fSMitch Phillips int pipefd[2];
95*e7c5e80fSMitch Phillips ASSERT_EQ(0, pipe2(pipefd, O_CLOEXEC));
96*e7c5e80fSMitch Phillips pid_t forkpid = fork();
97*e7c5e80fSMitch Phillips
98*e7c5e80fSMitch Phillips ASSERT_NE(-1, forkpid);
99*e7c5e80fSMitch Phillips if (forkpid == 0) {
100*e7c5e80fSMitch Phillips close(pipefd[1]);
101*e7c5e80fSMitch Phillips char buf;
102*e7c5e80fSMitch Phillips TEMP_FAILURE_RETRY(read(pipefd[0], &buf, 1));
103*e7c5e80fSMitch Phillips _exit(0);
104*e7c5e80fSMitch Phillips }
105*e7c5e80fSMitch Phillips
106*e7c5e80fSMitch Phillips
107*e7c5e80fSMitch Phillips // Give the child some time to get to the read.
108*e7c5e80fSMitch Phillips android::procinfo::ProcessInfo procinfo;
109*e7c5e80fSMitch Phillips for (int loop = 0; loop < 50 && procinfo.state != android::procinfo::kProcessStateSleeping; loop++) {
110*e7c5e80fSMitch Phillips std::this_thread::sleep_for(100ms);
111*e7c5e80fSMitch Phillips ASSERT_TRUE(android::procinfo::GetProcessInfo(forkpid, &procinfo));
112*e7c5e80fSMitch Phillips }
113*e7c5e80fSMitch Phillips ASSERT_EQ(android::procinfo::kProcessStateSleeping, procinfo.state);
114*e7c5e80fSMitch Phillips
115*e7c5e80fSMitch Phillips ASSERT_EQ(0, kill(forkpid, SIGKILL));
116*e7c5e80fSMitch Phillips
117*e7c5e80fSMitch Phillips // Give the kernel some time to kill the child.
118*e7c5e80fSMitch Phillips for (int loop = 0; loop < 50 && procinfo.state != android::procinfo::kProcessStateZombie; loop++) {
119*e7c5e80fSMitch Phillips std::this_thread::sleep_for(100ms);
120*e7c5e80fSMitch Phillips ASSERT_TRUE(android::procinfo::GetProcessInfo(forkpid, &procinfo));
121*e7c5e80fSMitch Phillips }
122*e7c5e80fSMitch Phillips ASSERT_EQ(android::procinfo::kProcessStateZombie, procinfo.state);
123*e7c5e80fSMitch Phillips
124*e7c5e80fSMitch Phillips ASSERT_EQ(forkpid, waitpid(forkpid, nullptr, 0));
125*e7c5e80fSMitch Phillips }
126*e7c5e80fSMitch Phillips
read_uptime_secs()127*e7c5e80fSMitch Phillips static uint64_t read_uptime_secs() {
128*e7c5e80fSMitch Phillips std::string uptime;
129*e7c5e80fSMitch Phillips if (!android::base::ReadFileToString("/proc/uptime", &uptime)) {
130*e7c5e80fSMitch Phillips PLOG(FATAL) << "failed to read /proc/uptime";
131*e7c5e80fSMitch Phillips }
132*e7c5e80fSMitch Phillips return strtoll(uptime.c_str(), nullptr, 10);
133*e7c5e80fSMitch Phillips }
134*e7c5e80fSMitch Phillips
TEST(process_info,process_start_time)135*e7c5e80fSMitch Phillips TEST(process_info, process_start_time) {
136*e7c5e80fSMitch Phillips uint64_t start = read_uptime_secs();
137*e7c5e80fSMitch Phillips int pipefd[2];
138*e7c5e80fSMitch Phillips ASSERT_EQ(0, pipe2(pipefd, O_CLOEXEC));
139*e7c5e80fSMitch Phillips
140*e7c5e80fSMitch Phillips std::this_thread::sleep_for(1000ms);
141*e7c5e80fSMitch Phillips
142*e7c5e80fSMitch Phillips pid_t forkpid = fork();
143*e7c5e80fSMitch Phillips
144*e7c5e80fSMitch Phillips ASSERT_NE(-1, forkpid);
145*e7c5e80fSMitch Phillips if (forkpid == 0) {
146*e7c5e80fSMitch Phillips close(pipefd[1]);
147*e7c5e80fSMitch Phillips char buf;
148*e7c5e80fSMitch Phillips TEMP_FAILURE_RETRY(read(pipefd[0], &buf, 1));
149*e7c5e80fSMitch Phillips _exit(0);
150*e7c5e80fSMitch Phillips }
151*e7c5e80fSMitch Phillips
152*e7c5e80fSMitch Phillips std::this_thread::sleep_for(1000ms);
153*e7c5e80fSMitch Phillips
154*e7c5e80fSMitch Phillips uint64_t end = read_uptime_secs();
155*e7c5e80fSMitch Phillips
156*e7c5e80fSMitch Phillips android::procinfo::ProcessInfo procinfo;
157*e7c5e80fSMitch Phillips ASSERT_TRUE(android::procinfo::GetProcessInfo(forkpid, &procinfo));
158*e7c5e80fSMitch Phillips
159*e7c5e80fSMitch Phillips // starttime is measured in clock ticks: uptime is in seconds:
160*e7c5e80fSMitch Phillips uint64_t process_start = procinfo.starttime / sysconf(_SC_CLK_TCK);
161*e7c5e80fSMitch Phillips ASSERT_LE(start, process_start);
162*e7c5e80fSMitch Phillips ASSERT_LE(process_start, end);
163*e7c5e80fSMitch Phillips
164*e7c5e80fSMitch Phillips ASSERT_EQ(0, kill(forkpid, SIGKILL));
165*e7c5e80fSMitch Phillips ASSERT_EQ(forkpid, waitpid(forkpid, nullptr, 0));
166*e7c5e80fSMitch Phillips }
167*e7c5e80fSMitch Phillips
TEST(process_info,GetProcessInfoFromProcPidFd_set_error)168*e7c5e80fSMitch Phillips TEST(process_info, GetProcessInfoFromProcPidFd_set_error) {
169*e7c5e80fSMitch Phillips TemporaryDir tmp_dir;
170*e7c5e80fSMitch Phillips
171*e7c5e80fSMitch Phillips android::base::unique_fd dirfd(open(tmp_dir.path, O_DIRECTORY | O_RDONLY));
172*e7c5e80fSMitch Phillips android::procinfo::ProcessInfo procinfo;
173*e7c5e80fSMitch Phillips std::string error;
174*e7c5e80fSMitch Phillips
175*e7c5e80fSMitch Phillips // failed to open status file error
176*e7c5e80fSMitch Phillips // No segfault if not given error string.
177*e7c5e80fSMitch Phillips ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), 0, &procinfo));
178*e7c5e80fSMitch Phillips // Set error when given error string.
179*e7c5e80fSMitch Phillips ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), 0, &procinfo, &error));
180*e7c5e80fSMitch Phillips ASSERT_EQ(error, "failed to open /proc/0/status in GetProcessInfoFromProcPidFd: No such file or directory");
181*e7c5e80fSMitch Phillips
182*e7c5e80fSMitch Phillips // failed to parse status file error
183*e7c5e80fSMitch Phillips std::string status_file = std::string(tmp_dir.path) + "/status";
184*e7c5e80fSMitch Phillips ASSERT_TRUE(android::base::WriteStringToFile("invalid data", status_file));
185*e7c5e80fSMitch Phillips ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), 0, &procinfo));
186*e7c5e80fSMitch Phillips ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), 0, &procinfo, &error));
187*e7c5e80fSMitch Phillips ASSERT_EQ(error, "failed to parse /proc/0/status");
188*e7c5e80fSMitch Phillips
189*e7c5e80fSMitch Phillips // Give the "/status" file valid contents.
190*e7c5e80fSMitch Phillips ASSERT_TRUE(android::base::WriteStringToFile(
191*e7c5e80fSMitch Phillips "Name:\tsh\nTgid:\t0\nPid:\t0\nTracerPid:\t0\nUid:\t0\nGid:\t0\n", status_file));
192*e7c5e80fSMitch Phillips
193*e7c5e80fSMitch Phillips // failed to open stat file error
194*e7c5e80fSMitch Phillips ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), 0, &procinfo));
195*e7c5e80fSMitch Phillips ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), 0, &procinfo, &error));
196*e7c5e80fSMitch Phillips ASSERT_EQ(error, "failed to open /proc/0/stat: No such file or directory");
197*e7c5e80fSMitch Phillips
198*e7c5e80fSMitch Phillips // failed to parse stat file error
199*e7c5e80fSMitch Phillips std::string stat_file = std::string(tmp_dir.path) + "/stat";
200*e7c5e80fSMitch Phillips ASSERT_TRUE(android::base::WriteStringToFile("2027 (sh) invalid data", stat_file));
201*e7c5e80fSMitch Phillips ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), 0, &procinfo));
202*e7c5e80fSMitch Phillips ASSERT_FALSE(android::procinfo::GetProcessInfoFromProcPidFd(dirfd.get(), 0, &procinfo, &error));
203*e7c5e80fSMitch Phillips ASSERT_EQ(error, "failed to parse /proc/0/stat");
204*e7c5e80fSMitch Phillips }
205