1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/process/process.h"
6
7 #include <utility>
8
9 #include "base/at_exit.h"
10 #include "base/process/kill.h"
11 #include "base/test/multiprocess_test.h"
12 #include "base/test/test_timeouts.h"
13 #include "base/threading/platform_thread.h"
14 #include "base/threading/thread_local.h"
15 #include "build/build_config.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "testing/multiprocess_func_list.h"
18
19 namespace {
20
21 #if defined(OS_WIN)
22 const int kExpectedStillRunningExitCode = 0x102;
23 #else
24 const int kExpectedStillRunningExitCode = 0;
25 #endif
26
27 #if defined(OS_MACOSX)
28 // Fake port provider that returns the calling process's
29 // task port, ignoring its argument.
30 class FakePortProvider : public base::PortProvider {
TaskForPid(base::ProcessHandle process) const31 mach_port_t TaskForPid(base::ProcessHandle process) const override {
32 return mach_task_self();
33 }
34 };
35 #endif
36
37 } // namespace
38
39 namespace base {
40
41 class ProcessTest : public MultiProcessTest {
42 };
43
TEST_F(ProcessTest,Create)44 TEST_F(ProcessTest, Create) {
45 Process process(SpawnChild("SimpleChildProcess"));
46 ASSERT_TRUE(process.IsValid());
47 ASSERT_FALSE(process.is_current());
48 EXPECT_NE(process.Pid(), kNullProcessId);
49 process.Close();
50 ASSERT_FALSE(process.IsValid());
51 }
52
TEST_F(ProcessTest,CreateCurrent)53 TEST_F(ProcessTest, CreateCurrent) {
54 Process process = Process::Current();
55 ASSERT_TRUE(process.IsValid());
56 ASSERT_TRUE(process.is_current());
57 EXPECT_NE(process.Pid(), kNullProcessId);
58 process.Close();
59 ASSERT_FALSE(process.IsValid());
60 }
61
TEST_F(ProcessTest,Move)62 TEST_F(ProcessTest, Move) {
63 Process process1(SpawnChild("SimpleChildProcess"));
64 EXPECT_TRUE(process1.IsValid());
65
66 Process process2;
67 EXPECT_FALSE(process2.IsValid());
68
69 process2 = std::move(process1);
70 EXPECT_TRUE(process2.IsValid());
71 EXPECT_FALSE(process1.IsValid());
72 EXPECT_FALSE(process2.is_current());
73
74 Process process3 = Process::Current();
75 process2 = std::move(process3);
76 EXPECT_TRUE(process2.is_current());
77 EXPECT_TRUE(process2.IsValid());
78 EXPECT_FALSE(process3.IsValid());
79 }
80
TEST_F(ProcessTest,Duplicate)81 TEST_F(ProcessTest, Duplicate) {
82 Process process1(SpawnChild("SimpleChildProcess"));
83 ASSERT_TRUE(process1.IsValid());
84
85 Process process2 = process1.Duplicate();
86 ASSERT_TRUE(process1.IsValid());
87 ASSERT_TRUE(process2.IsValid());
88 EXPECT_EQ(process1.Pid(), process2.Pid());
89 EXPECT_FALSE(process1.is_current());
90 EXPECT_FALSE(process2.is_current());
91
92 process1.Close();
93 ASSERT_TRUE(process2.IsValid());
94 }
95
TEST_F(ProcessTest,DuplicateCurrent)96 TEST_F(ProcessTest, DuplicateCurrent) {
97 Process process1 = Process::Current();
98 ASSERT_TRUE(process1.IsValid());
99
100 Process process2 = process1.Duplicate();
101 ASSERT_TRUE(process1.IsValid());
102 ASSERT_TRUE(process2.IsValid());
103 EXPECT_EQ(process1.Pid(), process2.Pid());
104 EXPECT_TRUE(process1.is_current());
105 EXPECT_TRUE(process2.is_current());
106
107 process1.Close();
108 ASSERT_TRUE(process2.IsValid());
109 }
110
TEST_F(ProcessTest,DeprecatedGetProcessFromHandle)111 TEST_F(ProcessTest, DeprecatedGetProcessFromHandle) {
112 Process process1(SpawnChild("SimpleChildProcess"));
113 ASSERT_TRUE(process1.IsValid());
114
115 Process process2 = Process::DeprecatedGetProcessFromHandle(process1.Handle());
116 ASSERT_TRUE(process1.IsValid());
117 ASSERT_TRUE(process2.IsValid());
118 EXPECT_EQ(process1.Pid(), process2.Pid());
119 EXPECT_FALSE(process1.is_current());
120 EXPECT_FALSE(process2.is_current());
121
122 process1.Close();
123 ASSERT_TRUE(process2.IsValid());
124 }
125
MULTIPROCESS_TEST_MAIN(SleepyChildProcess)126 MULTIPROCESS_TEST_MAIN(SleepyChildProcess) {
127 PlatformThread::Sleep(TestTimeouts::action_max_timeout());
128 return 0;
129 }
130
TEST_F(ProcessTest,Terminate)131 TEST_F(ProcessTest, Terminate) {
132 Process process(SpawnChild("SleepyChildProcess"));
133 ASSERT_TRUE(process.IsValid());
134
135 const int kDummyExitCode = 42;
136 int exit_code = kDummyExitCode;
137 EXPECT_EQ(TERMINATION_STATUS_STILL_RUNNING,
138 GetTerminationStatus(process.Handle(), &exit_code));
139 EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
140
141 exit_code = kDummyExitCode;
142 int kExpectedExitCode = 250;
143 process.Terminate(kExpectedExitCode, false);
144 process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(),
145 &exit_code);
146
147 EXPECT_NE(TERMINATION_STATUS_STILL_RUNNING,
148 GetTerminationStatus(process.Handle(), &exit_code));
149 #if !defined(OS_POSIX) && !defined(OS_FUCHSIA)
150 // The POSIX & Fuchsia implementations actually ignore the exit_code.
151 EXPECT_EQ(kExpectedExitCode, exit_code);
152 #endif
153 }
154
AtExitHandler(void *)155 void AtExitHandler(void*) {
156 // At-exit handler should not be called at
157 // Process::TerminateCurrentProcessImmediately.
158 DCHECK(false);
159 }
160
161 class ThreadLocalObject {
~ThreadLocalObject()162 ~ThreadLocalObject() {
163 // Thread-local storage should not be destructed at
164 // Process::TerminateCurrentProcessImmediately.
165 DCHECK(false);
166 }
167 };
168
MULTIPROCESS_TEST_MAIN(TerminateCurrentProcessImmediatelyWithCode0)169 MULTIPROCESS_TEST_MAIN(TerminateCurrentProcessImmediatelyWithCode0) {
170 base::ThreadLocalPointer<ThreadLocalObject> object;
171 base::AtExitManager::RegisterCallback(&AtExitHandler, nullptr);
172 Process::TerminateCurrentProcessImmediately(0);
173 }
174
TEST_F(ProcessTest,TerminateCurrentProcessImmediatelyWithZeroExitCode)175 TEST_F(ProcessTest, TerminateCurrentProcessImmediatelyWithZeroExitCode) {
176 Process process(SpawnChild("TerminateCurrentProcessImmediatelyWithCode0"));
177 ASSERT_TRUE(process.IsValid());
178 int exit_code = 42;
179 ASSERT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(),
180 &exit_code));
181 EXPECT_EQ(0, exit_code);
182 }
183
MULTIPROCESS_TEST_MAIN(TerminateCurrentProcessImmediatelyWithCode250)184 MULTIPROCESS_TEST_MAIN(TerminateCurrentProcessImmediatelyWithCode250) {
185 Process::TerminateCurrentProcessImmediately(250);
186 }
187
TEST_F(ProcessTest,TerminateCurrentProcessImmediatelyWithNonZeroExitCode)188 TEST_F(ProcessTest, TerminateCurrentProcessImmediatelyWithNonZeroExitCode) {
189 Process process(SpawnChild("TerminateCurrentProcessImmediatelyWithCode250"));
190 ASSERT_TRUE(process.IsValid());
191 int exit_code = 42;
192 ASSERT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(),
193 &exit_code));
194 EXPECT_EQ(250, exit_code);
195 }
196
MULTIPROCESS_TEST_MAIN(FastSleepyChildProcess)197 MULTIPROCESS_TEST_MAIN(FastSleepyChildProcess) {
198 PlatformThread::Sleep(TestTimeouts::tiny_timeout() * 10);
199 return 0;
200 }
201
TEST_F(ProcessTest,WaitForExit)202 TEST_F(ProcessTest, WaitForExit) {
203 Process process(SpawnChild("FastSleepyChildProcess"));
204 ASSERT_TRUE(process.IsValid());
205
206 const int kDummyExitCode = 42;
207 int exit_code = kDummyExitCode;
208 EXPECT_TRUE(process.WaitForExit(&exit_code));
209 EXPECT_EQ(0, exit_code);
210 }
211
TEST_F(ProcessTest,WaitForExitWithTimeout)212 TEST_F(ProcessTest, WaitForExitWithTimeout) {
213 Process process(SpawnChild("SleepyChildProcess"));
214 ASSERT_TRUE(process.IsValid());
215
216 const int kDummyExitCode = 42;
217 int exit_code = kDummyExitCode;
218 TimeDelta timeout = TestTimeouts::tiny_timeout();
219 EXPECT_FALSE(process.WaitForExitWithTimeout(timeout, &exit_code));
220 EXPECT_EQ(kDummyExitCode, exit_code);
221
222 process.Terminate(kDummyExitCode, false);
223 }
224
225 // Ensure that the priority of a process is restored correctly after
226 // backgrounding and restoring.
227 // Note: a platform may not be willing or able to lower the priority of
228 // a process. The calls to SetProcessBackground should be noops then.
TEST_F(ProcessTest,SetProcessBackgrounded)229 TEST_F(ProcessTest, SetProcessBackgrounded) {
230 if (!Process::CanBackgroundProcesses())
231 return;
232 Process process(SpawnChild("SimpleChildProcess"));
233 int old_priority = process.GetPriority();
234 #if defined(OS_WIN)
235 EXPECT_TRUE(process.SetProcessBackgrounded(true));
236 EXPECT_TRUE(process.IsProcessBackgrounded());
237 EXPECT_TRUE(process.SetProcessBackgrounded(false));
238 EXPECT_FALSE(process.IsProcessBackgrounded());
239 #elif defined(OS_MACOSX)
240 // On the Mac, backgrounding a process requires a port to that process.
241 // In the browser it's available through the MachBroker class, which is not
242 // part of base. Additionally, there is an indefinite amount of time between
243 // spawning a process and receiving its port. Because this test just checks
244 // the ability to background/foreground a process, we can use the current
245 // process's port instead.
246 FakePortProvider provider;
247 EXPECT_TRUE(process.SetProcessBackgrounded(&provider, true));
248 EXPECT_TRUE(process.IsProcessBackgrounded(&provider));
249 EXPECT_TRUE(process.SetProcessBackgrounded(&provider, false));
250 EXPECT_FALSE(process.IsProcessBackgrounded(&provider));
251
252 #else
253 process.SetProcessBackgrounded(true);
254 process.SetProcessBackgrounded(false);
255 #endif
256 int new_priority = process.GetPriority();
257 EXPECT_EQ(old_priority, new_priority);
258 }
259
260 // Same as SetProcessBackgrounded but to this very process. It uses
261 // a different code path at least for Windows.
TEST_F(ProcessTest,SetProcessBackgroundedSelf)262 TEST_F(ProcessTest, SetProcessBackgroundedSelf) {
263 if (!Process::CanBackgroundProcesses())
264 return;
265 Process process = Process::Current();
266 int old_priority = process.GetPriority();
267 #if defined(OS_WIN)
268 EXPECT_TRUE(process.SetProcessBackgrounded(true));
269 EXPECT_TRUE(process.IsProcessBackgrounded());
270 EXPECT_TRUE(process.SetProcessBackgrounded(false));
271 EXPECT_FALSE(process.IsProcessBackgrounded());
272 #elif defined(OS_MACOSX)
273 FakePortProvider provider;
274 EXPECT_TRUE(process.SetProcessBackgrounded(&provider, true));
275 EXPECT_TRUE(process.IsProcessBackgrounded(&provider));
276 EXPECT_TRUE(process.SetProcessBackgrounded(&provider, false));
277 EXPECT_FALSE(process.IsProcessBackgrounded(&provider));
278 #else
279 process.SetProcessBackgrounded(true);
280 process.SetProcessBackgrounded(false);
281 #endif
282 int new_priority = process.GetPriority();
283 EXPECT_EQ(old_priority, new_priority);
284 }
285
286 // Consumers can use WaitForExitWithTimeout(base::TimeDelta(), nullptr) to check
287 // whether the process is still running. This may not be safe because of the
288 // potential reusing of the process id. So we won't export Process::IsRunning()
289 // on all platforms. But for the controllable scenario in the test cases, the
290 // behavior should be guaranteed.
TEST_F(ProcessTest,CurrentProcessIsRunning)291 TEST_F(ProcessTest, CurrentProcessIsRunning) {
292 EXPECT_FALSE(Process::Current().WaitForExitWithTimeout(
293 base::TimeDelta(), nullptr));
294 }
295
296 #if defined(OS_MACOSX)
297 // On Mac OSX, we can detect whether a non-child process is running.
TEST_F(ProcessTest,PredefinedProcessIsRunning)298 TEST_F(ProcessTest, PredefinedProcessIsRunning) {
299 // Process 1 is the /sbin/launchd, it should be always running.
300 EXPECT_FALSE(Process::Open(1).WaitForExitWithTimeout(
301 base::TimeDelta(), nullptr));
302 }
303 #endif
304
TEST_F(ProcessTest,ChildProcessIsRunning)305 TEST_F(ProcessTest, ChildProcessIsRunning) {
306 Process process(SpawnChild("SleepyChildProcess"));
307 EXPECT_FALSE(process.WaitForExitWithTimeout(
308 base::TimeDelta(), nullptr));
309 process.Terminate(0, true);
310 EXPECT_TRUE(process.WaitForExitWithTimeout(
311 base::TimeDelta(), nullptr));
312 }
313
314 #if defined(OS_CHROMEOS)
315
316 // Tests that the function IsProcessBackgroundedCGroup() can parse the contents
317 // of the /proc/<pid>/cgroup file successfully.
TEST_F(ProcessTest,TestIsProcessBackgroundedCGroup)318 TEST_F(ProcessTest, TestIsProcessBackgroundedCGroup) {
319 const char kNotBackgrounded[] = "5:cpuacct,cpu,cpuset:/daemons\n";
320 const char kBackgrounded[] =
321 "2:freezer:/chrome_renderers/to_be_frozen\n"
322 "1:cpu:/chrome_renderers/background\n";
323
324 EXPECT_FALSE(IsProcessBackgroundedCGroup(kNotBackgrounded));
325 EXPECT_TRUE(IsProcessBackgroundedCGroup(kBackgrounded));
326 }
327
328 #endif // defined(OS_CHROMEOS)
329
330 } // namespace base
331