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