• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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