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 <chrono>
25 #include <set>
26 #include <thread>
27 #include <vector>
28 
29 #include <gtest/gtest.h>
30 
31 #include <android-base/file.h>
32 #include <android-base/logging.h>
33 #include <android-base/stringprintf.h>
34 #include <android-base/unique_fd.h>
35 
36 using namespace std::chrono_literals;
37 
38 #if !defined(__BIONIC__)
39 #include <syscall.h>
gettid()40 static pid_t gettid() {
41   return syscall(__NR_gettid);
42 }
43 #endif
44 
TEST(process_info,process_info_smoke)45 TEST(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 
TEST(process_info,process_info_proc_pid_fd_smoke)55 TEST(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 
TEST(process_info,process_tids_smoke)71 TEST(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 }
91 
TEST(process_info,process_state)92 TEST(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 }
122 
read_uptime_secs()123 static 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 
TEST(process_info,process_start_time)131 TEST(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 }
163 
TEST(process_info,GetProcessInfoFromProcPidFd_set_error)164 TEST(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 }
199