1 // Copyright 2014 The Chromium Authors
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 <memory>
8 #include <string>
9 #include <utility>
10
11 #include "base/at_exit.h"
12 #include "base/debug/invalid_access_win.h"
13 #include "base/process/kill.h"
14 #include "base/test/multiprocess_test.h"
15 #include "base/test/test_timeouts.h"
16 #include "base/threading/platform_thread.h"
17 #include "base/threading/platform_thread_internal_posix.h"
18 #include "base/threading/thread_local.h"
19 #include "build/build_config.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 #include "testing/multiprocess_func_list.h"
22
23 #if BUILDFLAG(IS_CHROMEOS)
24 #include <sys/resource.h>
25 #include <unistd.h>
26
27 #include <vector>
28
29 #include "base/files/file_path.h"
30 #include "base/files/file_util.h"
31 #include "base/process/internal_linux.h"
32 #include "base/strings/string_number_conversions.h"
33 #include "base/strings/string_split.h"
34 #include "base/strings/string_util.h"
35 #include "base/strings/stringprintf.h"
36 #include "base/test/scoped_feature_list.h"
37 #include "base/test/task_environment.h"
38 #include "base/time/time.h"
39 #endif // BUILDFLAG(IS_CHROMEOS)
40
41 #if BUILDFLAG(IS_WIN)
42 #include "base/win/base_win_buildflags.h"
43
44 #include <windows.h>
45 #endif
46
47 namespace {
48
49 #if BUILDFLAG(IS_WIN)
50 constexpr int kExpectedStillRunningExitCode = 0x102;
51 #else
52 constexpr int kExpectedStillRunningExitCode = 0;
53 #endif
54
55 constexpr int kDummyExitCode = 42;
56
57 #if BUILDFLAG(IS_APPLE)
58 // Fake port provider that returns the calling process's
59 // task port, ignoring its argument.
60 class FakePortProvider : public base::PortProvider {
TaskForPid(base::ProcessHandle process) const61 mach_port_t TaskForPid(base::ProcessHandle process) const override {
62 return mach_task_self();
63 }
64 };
65 #endif
66
67 #if BUILDFLAG(IS_CHROMEOS)
68 const char kForeground[] = "/chrome_renderers/foreground";
69 const char kCgroupRoot[] = "/sys/fs/cgroup/cpu";
70 const char kFullRendererCgroupRoot[] = "/sys/fs/cgroup/cpu/chrome_renderers";
71 const char kProcPath[] = "/proc/%d/cgroup";
72
GetProcessCpuCgroup(const base::Process & process)73 std::string GetProcessCpuCgroup(const base::Process& process) {
74 std::string proc;
75 if (!base::ReadFileToString(
76 base::FilePath(base::StringPrintf(kProcPath, process.Pid())),
77 &proc)) {
78 return std::string();
79 }
80
81 std::vector<base::StringPiece> lines = SplitStringPiece(
82 proc, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
83 for (const auto& line : lines) {
84 std::vector<base::StringPiece> fields = SplitStringPiece(
85 line, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
86 if (fields.size() != 3U) {
87 continue;
88 }
89
90 if (fields[1] == "cpu") {
91 return static_cast<std::string>(fields[2]);
92 }
93 }
94
95 return std::string();
96 }
97
AddProcessToCpuCgroup(const base::Process & process,const std::string & cgroup)98 bool AddProcessToCpuCgroup(const base::Process& process,
99 const std::string& cgroup) {
100 base::FilePath path(cgroup);
101 path = path.Append("cgroup.procs");
102 return base::WriteFile(path, base::NumberToString(process.Pid()));
103 }
104 #endif // BUILDFLAG(IS_CHROMEOS)
105
106 } // namespace
107
108 namespace base {
109
110 class ProcessTest : public MultiProcessTest {
111 };
112
TEST_F(ProcessTest,Create)113 TEST_F(ProcessTest, Create) {
114 Process process(SpawnChild("SimpleChildProcess"));
115 ASSERT_TRUE(process.IsValid());
116 ASSERT_FALSE(process.is_current());
117 EXPECT_NE(process.Pid(), kNullProcessId);
118 process.Close();
119 ASSERT_FALSE(process.IsValid());
120 }
121
TEST_F(ProcessTest,CreateCurrent)122 TEST_F(ProcessTest, CreateCurrent) {
123 Process process = Process::Current();
124 ASSERT_TRUE(process.IsValid());
125 ASSERT_TRUE(process.is_current());
126 EXPECT_NE(process.Pid(), kNullProcessId);
127 process.Close();
128 ASSERT_FALSE(process.IsValid());
129 }
130
TEST_F(ProcessTest,Move)131 TEST_F(ProcessTest, Move) {
132 Process process1(SpawnChild("SimpleChildProcess"));
133 EXPECT_TRUE(process1.IsValid());
134
135 Process process2;
136 EXPECT_FALSE(process2.IsValid());
137
138 process2 = std::move(process1);
139 EXPECT_TRUE(process2.IsValid());
140 EXPECT_FALSE(process1.IsValid());
141 EXPECT_FALSE(process2.is_current());
142
143 Process process3 = Process::Current();
144 process2 = std::move(process3);
145 EXPECT_TRUE(process2.is_current());
146 EXPECT_TRUE(process2.IsValid());
147 EXPECT_FALSE(process3.IsValid());
148 }
149
TEST_F(ProcessTest,Duplicate)150 TEST_F(ProcessTest, Duplicate) {
151 Process process1(SpawnChild("SimpleChildProcess"));
152 ASSERT_TRUE(process1.IsValid());
153
154 Process process2 = process1.Duplicate();
155 ASSERT_TRUE(process1.IsValid());
156 ASSERT_TRUE(process2.IsValid());
157 EXPECT_EQ(process1.Pid(), process2.Pid());
158 EXPECT_FALSE(process1.is_current());
159 EXPECT_FALSE(process2.is_current());
160
161 process1.Close();
162 ASSERT_TRUE(process2.IsValid());
163 }
164
TEST_F(ProcessTest,DuplicateCurrent)165 TEST_F(ProcessTest, DuplicateCurrent) {
166 Process process1 = Process::Current();
167 ASSERT_TRUE(process1.IsValid());
168
169 Process process2 = process1.Duplicate();
170 ASSERT_TRUE(process1.IsValid());
171 ASSERT_TRUE(process2.IsValid());
172 EXPECT_EQ(process1.Pid(), process2.Pid());
173 EXPECT_TRUE(process1.is_current());
174 EXPECT_TRUE(process2.is_current());
175
176 process1.Close();
177 ASSERT_TRUE(process2.IsValid());
178 }
179
MULTIPROCESS_TEST_MAIN(SleepyChildProcess)180 MULTIPROCESS_TEST_MAIN(SleepyChildProcess) {
181 PlatformThread::Sleep(TestTimeouts::action_max_timeout());
182 return 0;
183 }
184
185 // TODO(https://crbug.com/726484): Enable these tests on Fuchsia when
186 // CreationTime() is implemented.
TEST_F(ProcessTest,CreationTimeCurrentProcess)187 TEST_F(ProcessTest, CreationTimeCurrentProcess) {
188 // The current process creation time should be less than or equal to the
189 // current time.
190 EXPECT_FALSE(Process::Current().CreationTime().is_null());
191 EXPECT_LE(Process::Current().CreationTime(), Time::Now());
192 }
193
194 #if !BUILDFLAG(IS_ANDROID) // Cannot read other processes' creation time on
195 // Android.
TEST_F(ProcessTest,CreationTimeOtherProcess)196 TEST_F(ProcessTest, CreationTimeOtherProcess) {
197 // The creation time of a process should be between a time recorded before it
198 // was spawned and a time recorded after it was spawned. However, since the
199 // base::Time and process creation clocks don't match, tolerate some error.
200 constexpr base::TimeDelta kTolerance =
201 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
202 // On Linux, process creation time is relative to boot time which has a
203 // 1-second resolution. Tolerate 1 second for the imprecise boot time and
204 // 100 ms for the imprecise clock.
205 Milliseconds(1100);
206 #elif BUILDFLAG(IS_WIN)
207 // On Windows, process creation time is based on the system clock while
208 // Time::Now() is a combination of system clock and
209 // QueryPerformanceCounter(). Tolerate 100 ms for the clock mismatch.
210 Milliseconds(100);
211 #elif BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_FUCHSIA)
212 // On Mac and Fuchsia, process creation time should be very precise.
213 Milliseconds(0);
214 #else
215 #error Unsupported platform
216 #endif
217 const Time before_creation = Time::Now();
218 Process process(SpawnChild("SleepyChildProcess"));
219 const Time after_creation = Time::Now();
220 const Time creation = process.CreationTime();
221 EXPECT_LE(before_creation - kTolerance, creation);
222 EXPECT_LE(creation, after_creation + kTolerance);
223 EXPECT_TRUE(process.Terminate(kDummyExitCode, true));
224 }
225 #endif // !BUILDFLAG(IS_ANDROID)
226
TEST_F(ProcessTest,Terminate)227 TEST_F(ProcessTest, Terminate) {
228 Process process(SpawnChild("SleepyChildProcess"));
229 ASSERT_TRUE(process.IsValid());
230
231 int exit_code = kDummyExitCode;
232 EXPECT_EQ(TERMINATION_STATUS_STILL_RUNNING,
233 GetTerminationStatus(process.Handle(), &exit_code));
234 EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
235
236 exit_code = kDummyExitCode;
237 int kExpectedExitCode = 250;
238 process.Terminate(kExpectedExitCode, false);
239 process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(),
240 &exit_code);
241
242 EXPECT_NE(TERMINATION_STATUS_STILL_RUNNING,
243 GetTerminationStatus(process.Handle(), &exit_code));
244 #if BUILDFLAG(IS_WIN)
245 // Only Windows propagates the |exit_code| set in Terminate().
246 EXPECT_EQ(kExpectedExitCode, exit_code);
247 #endif
248 }
249
AtExitHandler(void *)250 void AtExitHandler(void*) {
251 // At-exit handler should not be called at
252 // Process::TerminateCurrentProcessImmediately.
253 DCHECK(false);
254 }
255
256 class ThreadLocalObject {
257 public:
~ThreadLocalObject()258 ~ThreadLocalObject() {
259 // Thread-local storage should not be destructed at
260 // Process::TerminateCurrentProcessImmediately.
261 DCHECK(false);
262 }
263 };
264
MULTIPROCESS_TEST_MAIN(TerminateCurrentProcessImmediatelyWithCode0)265 MULTIPROCESS_TEST_MAIN(TerminateCurrentProcessImmediatelyWithCode0) {
266 base::ThreadLocalOwnedPointer<ThreadLocalObject> object;
267 object.Set(std::make_unique<ThreadLocalObject>());
268 base::AtExitManager::RegisterCallback(&AtExitHandler, nullptr);
269 Process::TerminateCurrentProcessImmediately(0);
270 }
271
TEST_F(ProcessTest,TerminateCurrentProcessImmediatelyWithZeroExitCode)272 TEST_F(ProcessTest, TerminateCurrentProcessImmediatelyWithZeroExitCode) {
273 Process process(SpawnChild("TerminateCurrentProcessImmediatelyWithCode0"));
274 ASSERT_TRUE(process.IsValid());
275 int exit_code = 42;
276 ASSERT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(),
277 &exit_code));
278 EXPECT_EQ(0, exit_code);
279 }
280
MULTIPROCESS_TEST_MAIN(TerminateCurrentProcessImmediatelyWithCode250)281 MULTIPROCESS_TEST_MAIN(TerminateCurrentProcessImmediatelyWithCode250) {
282 Process::TerminateCurrentProcessImmediately(250);
283 }
284
TEST_F(ProcessTest,TerminateCurrentProcessImmediatelyWithNonZeroExitCode)285 TEST_F(ProcessTest, TerminateCurrentProcessImmediatelyWithNonZeroExitCode) {
286 Process process(SpawnChild("TerminateCurrentProcessImmediatelyWithCode250"));
287 ASSERT_TRUE(process.IsValid());
288 int exit_code = 42;
289 ASSERT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(),
290 &exit_code));
291 EXPECT_EQ(250, exit_code);
292 }
293
MULTIPROCESS_TEST_MAIN(FastSleepyChildProcess)294 MULTIPROCESS_TEST_MAIN(FastSleepyChildProcess) {
295 PlatformThread::Sleep(TestTimeouts::tiny_timeout() * 10);
296 return 0;
297 }
298
TEST_F(ProcessTest,WaitForExit)299 TEST_F(ProcessTest, WaitForExit) {
300 Process process(SpawnChild("FastSleepyChildProcess"));
301 ASSERT_TRUE(process.IsValid());
302
303 int exit_code = kDummyExitCode;
304 EXPECT_TRUE(process.WaitForExit(&exit_code));
305 EXPECT_EQ(0, exit_code);
306 }
307
TEST_F(ProcessTest,WaitForExitWithTimeout)308 TEST_F(ProcessTest, WaitForExitWithTimeout) {
309 Process process(SpawnChild("SleepyChildProcess"));
310 ASSERT_TRUE(process.IsValid());
311
312 int exit_code = kDummyExitCode;
313 TimeDelta timeout = TestTimeouts::tiny_timeout();
314 EXPECT_FALSE(process.WaitForExitWithTimeout(timeout, &exit_code));
315 EXPECT_EQ(kDummyExitCode, exit_code);
316
317 process.Terminate(kDummyExitCode, false);
318 }
319
320 #if BUILDFLAG(IS_WIN)
TEST_F(ProcessTest,WaitForExitOrEventWithProcessExit)321 TEST_F(ProcessTest, WaitForExitOrEventWithProcessExit) {
322 Process process(SpawnChild("FastSleepyChildProcess"));
323 ASSERT_TRUE(process.IsValid());
324
325 base::win::ScopedHandle stop_watching_handle(
326 CreateEvent(nullptr, TRUE, FALSE, nullptr));
327
328 int exit_code = kDummyExitCode;
329 EXPECT_EQ(process.WaitForExitOrEvent(stop_watching_handle, &exit_code),
330 base::Process::WaitExitStatus::PROCESS_EXITED);
331 EXPECT_EQ(0, exit_code);
332 }
333
TEST_F(ProcessTest,WaitForExitOrEventWithEventSet)334 TEST_F(ProcessTest, WaitForExitOrEventWithEventSet) {
335 Process process(SpawnChild("SleepyChildProcess"));
336 ASSERT_TRUE(process.IsValid());
337
338 base::win::ScopedHandle stop_watching_handle(
339 CreateEvent(nullptr, TRUE, TRUE, nullptr));
340
341 int exit_code = kDummyExitCode;
342 EXPECT_EQ(process.WaitForExitOrEvent(stop_watching_handle, &exit_code),
343 base::Process::WaitExitStatus::STOP_EVENT_SIGNALED);
344 EXPECT_EQ(kDummyExitCode, exit_code);
345
346 process.Terminate(kDummyExitCode, false);
347 }
348 #endif // BUILDFLAG(IS_WIN)
349
350 // Ensure that the priority of a process is restored correctly after
351 // backgrounding and restoring.
352 // Note: a platform may not be willing or able to lower the priority of
353 // a process. The calls to SetProcessPriority should be noops then.
TEST_F(ProcessTest,SetProcessPriority)354 TEST_F(ProcessTest, SetProcessPriority) {
355 if (!Process::CanSetPriority()) {
356 return;
357 }
358 Process process(SpawnChild("SimpleChildProcess"));
359 int old_os_priority = process.GetOSPriority();
360 #if BUILDFLAG(IS_APPLE)
361 // On the Mac, backgrounding a process requires a port to that process.
362 // In the browser it's available through the MachBroker class, which is not
363 // part of base. Additionally, there is an indefinite amount of time between
364 // spawning a process and receiving its port. Because this test just checks
365 // the ability to background/foreground a process, we can use the current
366 // process's port instead.
367 FakePortProvider provider;
368 EXPECT_TRUE(process.SetPriority(&provider, Process::Priority::kBestEffort));
369 EXPECT_EQ(process.GetPriority(&provider), Process::Priority::kBestEffort);
370 EXPECT_TRUE(process.SetPriority(&provider, Process::Priority::kUserBlocking));
371 EXPECT_EQ(process.GetPriority(&provider), Process::Priority::kUserBlocking);
372
373 #else
374 EXPECT_TRUE(process.SetPriority(base::Process::Priority::kBestEffort));
375 EXPECT_EQ(process.GetPriority(), Process::Priority::kBestEffort);
376 EXPECT_TRUE(process.SetPriority(base::Process::Priority::kUserBlocking));
377 EXPECT_EQ(process.GetPriority(), Process::Priority::kUserBlocking);
378 #endif
379 int new_os_priority = process.GetOSPriority();
380 EXPECT_EQ(old_os_priority, new_os_priority);
381 }
382
383 #if BUILDFLAG(IS_CHROMEOS)
384
385 namespace {
386
387 class FunctionTestThread : public PlatformThread::Delegate {
388 public:
389 FunctionTestThread() = default;
390
391 FunctionTestThread(const FunctionTestThread&) = delete;
392 FunctionTestThread& operator=(const FunctionTestThread&) = delete;
393
ThreadMain()394 void ThreadMain() override {
395 PlatformThread::SetCurrentThreadType(ThreadType::kCompositing);
396 while (true) {
397 PlatformThread::Sleep(Milliseconds(100));
398 }
399 }
400 };
401
402 class RTFunctionTestThread : public PlatformThread::Delegate {
403 public:
404 RTFunctionTestThread() = default;
405
406 RTFunctionTestThread(const RTFunctionTestThread&) = delete;
407 RTFunctionTestThread& operator=(const RTFunctionTestThread&) = delete;
408
ThreadMain()409 void ThreadMain() override {
410 PlatformThread::SetCurrentThreadType(ThreadType::kRealtimeAudio);
411 while (true) {
412 PlatformThread::Sleep(Milliseconds(100));
413 }
414 }
415 };
416
417 int create_threads_after_bg;
418 bool bg_threads_created;
419 bool prebg_threads_created;
420 bool rt_threads_created;
421
sig_create_threads_after_bg(int signum)422 void sig_create_threads_after_bg(int signum) {
423 if (signum == SIGUSR1) {
424 create_threads_after_bg = true;
425 }
426 }
427
sig_prebg_threads_created_handler(int signum)428 void sig_prebg_threads_created_handler(int signum) {
429 if (signum == SIGUSR1) {
430 prebg_threads_created = true;
431 }
432 }
433
sig_bg_threads_created_handler(int signum)434 void sig_bg_threads_created_handler(int signum) {
435 if (signum == SIGUSR2) {
436 bg_threads_created = true;
437 }
438 }
439
sig_rt_threads_created_handler(int signum)440 void sig_rt_threads_created_handler(int signum) {
441 if (signum == SIGUSR1) {
442 rt_threads_created = true;
443 }
444 }
445
446 } // namespace
447
MULTIPROCESS_TEST_MAIN(ProcessThreadBackgroundingMain)448 MULTIPROCESS_TEST_MAIN(ProcessThreadBackgroundingMain) {
449 PlatformThreadHandle handle1, handle2, handle3;
450 FunctionTestThread thread1, thread2, thread3;
451 PlatformThread::SetCurrentThreadType(ThreadType::kCompositing);
452
453 // Register signal handler to be notified to create threads after backgrounding.
454 signal(SIGUSR1, sig_create_threads_after_bg);
455
456 if (!PlatformThread::Create(0, &thread1, &handle1)) {
457 ADD_FAILURE() << "ProcessThreadBackgroundingMain: Failed to create thread1";
458 return 1;
459 }
460
461 if (!PlatformThread::Create(0, &thread2, &handle2)) {
462 ADD_FAILURE() << "ProcessThreadBackgroundingMain: Failed to create thread2";
463 return 1;
464 }
465
466 // Signal that the pre-backgrounding threads were created.
467 kill(getppid(), SIGUSR1);
468
469 // Wait for the signal to background.
470 while (create_threads_after_bg == 0) {
471 PlatformThread::Sleep(Milliseconds(100));
472 }
473
474 // Test creation of thread while process is backgrounded.
475 if (!PlatformThread::Create(0, &thread3, &handle3)) {
476 ADD_FAILURE() << "ProcessThreadBackgroundingMain: Failed to create thread3";
477 return 1;
478 }
479
480 // Signal that the thread after backgrounding was created.
481 kill(getppid(), SIGUSR2);
482
483 while (true) {
484 PlatformThread::Sleep(Milliseconds(100));
485 }
486 }
487
AssertCompositingThreadProperties(int process_id,bool backgrounded)488 void AssertCompositingThreadProperties(int process_id, bool backgrounded) {
489 internal::ForEachProcessTask(
490 process_id, [process_id, backgrounded](PlatformThreadId tid,
491 const FilePath& path) {
492 EXPECT_EQ(PlatformThread::GetThreadTypeFromThreadId(process_id, tid),
493 ThreadType::kCompositing);
494 EXPECT_EQ(PlatformThreadLinux::IsThreadBackgroundedForTest(tid),
495 backgrounded);
496 });
497 }
498
499 // ProcessThreadBackgrounding: A test to create a process and verify
500 // that the threads in the process are backgrounded correctly.
TEST_F(ProcessTest,ProcessThreadBackgrounding)501 TEST_F(ProcessTest, ProcessThreadBackgrounding) {
502 if (!PlatformThread::CanChangeThreadType(ThreadType::kDefault,
503 ThreadType::kCompositing)) {
504 return;
505 }
506
507 // Register signal handlers to be notified of events in child process.
508 signal(SIGUSR1, sig_prebg_threads_created_handler);
509 signal(SIGUSR2, sig_bg_threads_created_handler);
510
511 Process process(SpawnChild("ProcessThreadBackgroundingMain"));
512 EXPECT_TRUE(process.IsValid());
513
514 // Wait for the signal that the initial pre-backgrounding
515 // threads were created.
516 while (!prebg_threads_created) {
517 PlatformThread::Sleep(Milliseconds(100));
518 }
519
520 AssertCompositingThreadProperties(process.Pid(), false);
521
522 EXPECT_TRUE(process.SetPriority(Process::Priority::kBestEffort));
523
524 // Send a signal to create a thread while the process is backgrounded.
525 kill(process.Pid(), SIGUSR1);
526
527 // Wait for the signal that backgrounding completed
528 while (!bg_threads_created) {
529 PlatformThread::Sleep(Milliseconds(100));
530 }
531
532 AssertCompositingThreadProperties(process.Pid(), true);
533
534 EXPECT_TRUE(process.SetPriority(Process::Priority::kUserBlocking));
535 EXPECT_TRUE(process.GetPriority() == base::Process::Priority::kUserBlocking);
536
537 // Verify that type is restored to default after foregrounding.
538 AssertCompositingThreadProperties(process.Pid(), false);
539 }
540
IsThreadRT(PlatformThreadId thread_id)541 bool IsThreadRT(PlatformThreadId thread_id) {
542 PlatformThreadId syscall_tid = thread_id;
543 int sched;
544
545 if (thread_id == PlatformThread::CurrentId()) {
546 syscall_tid = 0;
547 }
548
549 // Check if the thread is running in real-time mode
550 sched = sched_getscheduler(syscall_tid);
551 if (sched == -1) {
552 // The thread may disappear for any reason so ignore ESRCH.
553 DPLOG_IF(ERROR, errno != ESRCH)
554 << "Failed to call sched_getscheduler for thread id " << thread_id;
555 return false;
556 }
557 return sched == SCHED_RR || sched == SCHED_FIFO;
558 }
559
560 // Verify that all the threads in a process are kRealtimeAudio
561 // and not backgrounded even though the process may be backgrounded.
AssertRTAudioThreadProperties(int process_id)562 void AssertRTAudioThreadProperties(int process_id) {
563 internal::ForEachProcessTask(
564 process_id, [process_id](PlatformThreadId tid, const FilePath& path) {
565 EXPECT_EQ(PlatformThread::GetThreadTypeFromThreadId(process_id, tid),
566 ThreadType::kRealtimeAudio);
567 EXPECT_EQ(IsThreadRT(tid), true);
568 EXPECT_EQ(PlatformThreadLinux::IsThreadBackgroundedForTest(tid), false);
569 });
570 }
571
MULTIPROCESS_TEST_MAIN(ProcessRTThreadBackgroundingMain)572 MULTIPROCESS_TEST_MAIN(ProcessRTThreadBackgroundingMain) {
573 PlatformThreadHandle handle1;
574 RTFunctionTestThread thread1;
575 PlatformThread::SetCurrentThreadType(ThreadType::kRealtimeAudio);
576
577 if (!PlatformThread::Create(0, &thread1, &handle1)) {
578 ADD_FAILURE()
579 << "ProcessRTThreadBackgroundingMain: Failed to create thread1";
580 return 1;
581 }
582
583 // Signal that the RT thread was created.
584 kill(getppid(), SIGUSR1);
585
586 while (true) {
587 PlatformThread::Sleep(Milliseconds(100));
588 }
589 }
590
591 // Test the property of kRealTimeAudio threads in a backgrounded process.
TEST_F(ProcessTest,ProcessRTThreadBackgrounding)592 TEST_F(ProcessTest, ProcessRTThreadBackgrounding) {
593 if (!PlatformThread::CanChangeThreadType(ThreadType::kDefault,
594 ThreadType::kCompositing)) {
595 return;
596 }
597
598 // Register signal handler to check if RT thread was created by child process.
599 signal(SIGUSR1, sig_rt_threads_created_handler);
600
601 Process process(SpawnChild("ProcessRTThreadBackgroundingMain"));
602 EXPECT_TRUE(process.IsValid());
603
604 // Wait for signal that threads were spawned
605 while (!rt_threads_created) {
606 PlatformThread::Sleep(Milliseconds(100));
607 }
608
609 AssertRTAudioThreadProperties(process.Pid());
610
611 EXPECT_TRUE(process.SetPriority(Process::Priority::kBestEffort));
612 EXPECT_TRUE(process.GetPriority() == base::Process::Priority::kBestEffort);
613
614 // Verify that nothing changed when process is kBestEffort
615 AssertRTAudioThreadProperties(process.Pid());
616
617 EXPECT_TRUE(process.SetPriority(Process::Priority::kUserBlocking));
618 EXPECT_TRUE(process.GetPriority() == base::Process::Priority::kUserBlocking);
619
620 // Verify that nothing changed when process is kUserBlocking
621 AssertRTAudioThreadProperties(process.Pid());
622 }
623
624 #endif // BUILDFLAG(IS_CHROMEOS)
625
626 // Consumers can use WaitForExitWithTimeout(base::TimeDelta(), nullptr) to check
627 // whether the process is still running. This may not be safe because of the
628 // potential reusing of the process id. So we won't export Process::IsRunning()
629 // on all platforms. But for the controllable scenario in the test cases, the
630 // behavior should be guaranteed.
TEST_F(ProcessTest,CurrentProcessIsRunning)631 TEST_F(ProcessTest, CurrentProcessIsRunning) {
632 EXPECT_FALSE(Process::Current().WaitForExitWithTimeout(
633 base::TimeDelta(), nullptr));
634 }
635
636 #if BUILDFLAG(IS_APPLE)
637 // On Mac OSX, we can detect whether a non-child process is running.
TEST_F(ProcessTest,PredefinedProcessIsRunning)638 TEST_F(ProcessTest, PredefinedProcessIsRunning) {
639 // Process 1 is the /sbin/launchd, it should be always running.
640 EXPECT_FALSE(Process::Open(1).WaitForExitWithTimeout(
641 base::TimeDelta(), nullptr));
642 }
643 #endif
644
645 // Test is disabled on Windows AMR64 because
646 // TerminateWithHeapCorruption() isn't expected to work there.
647 // See: https://crbug.com/1054423
648 #if BUILDFLAG(IS_WIN)
649 #if defined(ARCH_CPU_ARM64)
650 #define MAYBE_HeapCorruption DISABLED_HeapCorruption
651 #else
652 #define MAYBE_HeapCorruption HeapCorruption
653 #endif
TEST_F(ProcessTest,MAYBE_HeapCorruption)654 TEST_F(ProcessTest, MAYBE_HeapCorruption) {
655 EXPECT_EXIT(base::debug::win::TerminateWithHeapCorruption(),
656 ::testing::ExitedWithCode(STATUS_HEAP_CORRUPTION), "");
657 }
658
659 #if BUILDFLAG(WIN_ENABLE_CFG_GUARDS)
660 #define MAYBE_ControlFlowViolation ControlFlowViolation
661 #else
662 #define MAYBE_ControlFlowViolation DISABLED_ControlFlowViolation
663 #endif
TEST_F(ProcessTest,MAYBE_ControlFlowViolation)664 TEST_F(ProcessTest, MAYBE_ControlFlowViolation) {
665 // CFG causes ntdll!RtlFailFast2 to be called resulting in uncatchable
666 // 0xC0000409 (STATUS_STACK_BUFFER_OVERRUN) exception.
667 EXPECT_EXIT(base::debug::win::TerminateWithControlFlowViolation(),
668 ::testing::ExitedWithCode(STATUS_STACK_BUFFER_OVERRUN), "");
669 }
670
671 #endif // BUILDFLAG(IS_WIN)
672
TEST_F(ProcessTest,ChildProcessIsRunning)673 TEST_F(ProcessTest, ChildProcessIsRunning) {
674 Process process(SpawnChild("SleepyChildProcess"));
675 EXPECT_FALSE(process.WaitForExitWithTimeout(
676 base::TimeDelta(), nullptr));
677 process.Terminate(0, true);
678 EXPECT_TRUE(process.WaitForExitWithTimeout(
679 base::TimeDelta(), nullptr));
680 }
681
682 #if BUILDFLAG(IS_CHROMEOS)
683
684 // Tests that the function GetProcessPriorityCGroup() can parse the contents
685 // of the /proc/<pid>/cgroup file successfully.
TEST_F(ProcessTest,TestGetProcessPriorityCGroup)686 TEST_F(ProcessTest, TestGetProcessPriorityCGroup) {
687 const char kNotBackgroundedCGroup[] = "5:cpuacct,cpu,cpuset:/daemons\n";
688 const char kBackgroundedCGroup[] =
689 "2:freezer:/chrome_renderers/to_be_frozen\n"
690 "1:cpu:/chrome_renderers/background\n";
691
692 EXPECT_EQ(GetProcessPriorityCGroup(kNotBackgroundedCGroup),
693 Process::Priority::kUserBlocking);
694 EXPECT_EQ(GetProcessPriorityCGroup(kBackgroundedCGroup),
695 Process::Priority::kBestEffort);
696 }
697
TEST_F(ProcessTest,InitializePriorityEmptyProcess)698 TEST_F(ProcessTest, InitializePriorityEmptyProcess) {
699 // TODO(b/172213843): base::Process is used by base::TestSuite::Initialize
700 // before we can use ScopedFeatureList here. Update the test to allow the
701 // use of ScopedFeatureList before base::TestSuite::Initialize runs.
702 if (!Process::OneGroupPerRendererEnabledForTesting())
703 return;
704
705 Process process;
706 process.InitializePriority();
707 const std::string unique_token = process.unique_token();
708 ASSERT_TRUE(unique_token.empty());
709 }
710
TEST_F(ProcessTest,SetProcessBackgroundedOneCgroupPerRender)711 TEST_F(ProcessTest, SetProcessBackgroundedOneCgroupPerRender) {
712 if (!Process::OneGroupPerRendererEnabledForTesting())
713 return;
714
715 base::test::TaskEnvironment task_env;
716
717 Process process(SpawnChild("SimpleChildProcess"));
718 process.InitializePriority();
719 const std::string unique_token = process.unique_token();
720 ASSERT_FALSE(unique_token.empty());
721
722 EXPECT_TRUE(process.SetPriority(Process::Priority::kUserBlocking));
723 EXPECT_EQ(process.GetPriority(), Process::Priority::kUserBlocking);
724 std::string cgroup = GetProcessCpuCgroup(process);
725 EXPECT_FALSE(cgroup.empty());
726 EXPECT_NE(cgroup.find(unique_token), std::string::npos);
727
728 EXPECT_TRUE(process.SetPriority(Process::Priority::kBestEffort));
729 EXPECT_EQ(process.GetPriority(), Process::Priority::kBestEffort);
730
731 EXPECT_TRUE(process.Terminate(0, false));
732 // Terminate should post a task, wait for it to run
733 task_env.RunUntilIdle();
734
735 cgroup = std::string(kCgroupRoot) + cgroup;
736 EXPECT_FALSE(base::DirectoryExists(FilePath(cgroup)));
737 }
738
TEST_F(ProcessTest,CleanUpBusyProcess)739 TEST_F(ProcessTest, CleanUpBusyProcess) {
740 if (!Process::OneGroupPerRendererEnabledForTesting())
741 return;
742
743 base::test::TaskEnvironment task_env;
744
745 Process process(SpawnChild("SimpleChildProcess"));
746 process.InitializePriority();
747 const std::string unique_token = process.unique_token();
748 ASSERT_FALSE(unique_token.empty());
749
750 EXPECT_TRUE(process.SetPriority(Process::Priority::kUserBlocking));
751 EXPECT_EQ(process.GetPriority(), Process::Priority::kUserBlocking);
752 std::string cgroup = GetProcessCpuCgroup(process);
753 EXPECT_FALSE(cgroup.empty());
754 EXPECT_NE(cgroup.find(unique_token), std::string::npos);
755
756 // Add another process to the cgroup to ensure it stays busy.
757 cgroup = std::string(kCgroupRoot) + cgroup;
758 Process process2(SpawnChild("SimpleChildProcess"));
759 EXPECT_TRUE(AddProcessToCpuCgroup(process2, cgroup));
760
761 // Terminate the first process that should tirgger a cleanup of the cgroup
762 EXPECT_TRUE(process.Terminate(0, false));
763 // Wait until the background task runs once. This should fail and requeue
764 // another task to retry.
765 task_env.RunUntilIdle();
766 EXPECT_TRUE(base::DirectoryExists(FilePath(cgroup)));
767
768 // Move the second process to free the cgroup
769 std::string foreground_path =
770 std::string(kCgroupRoot) + std::string(kForeground);
771 EXPECT_TRUE(AddProcessToCpuCgroup(process2, foreground_path));
772
773 // Wait for the retry.
774 PlatformThread::Sleep(base::Milliseconds(1100));
775 task_env.RunUntilIdle();
776 // The cgroup should be deleted now.
777 EXPECT_FALSE(base::DirectoryExists(FilePath(cgroup)));
778
779 process2.Terminate(0, false);
780 }
781
TEST_F(ProcessTest,SetProcessBackgroundedEmptyToken)782 TEST_F(ProcessTest, SetProcessBackgroundedEmptyToken) {
783 if (!Process::OneGroupPerRendererEnabledForTesting())
784 return;
785
786 Process process(SpawnChild("SimpleChildProcess"));
787 const std::string unique_token = process.unique_token();
788 ASSERT_TRUE(unique_token.empty());
789
790 // Moving to the foreground should use the default foreground path.
791 EXPECT_TRUE(process.SetPriority(Process::Priority::kUserBlocking));
792 EXPECT_EQ(process.GetPriority(), Process::Priority::kUserBlocking);
793 std::string cgroup = GetProcessCpuCgroup(process);
794 EXPECT_FALSE(cgroup.empty());
795 EXPECT_EQ(cgroup, kForeground);
796 }
797
TEST_F(ProcessTest,CleansUpStaleGroups)798 TEST_F(ProcessTest, CleansUpStaleGroups) {
799 if (!Process::OneGroupPerRendererEnabledForTesting())
800 return;
801
802 base::test::TaskEnvironment task_env;
803
804 // Create a process that will not be cleaned up
805 Process process(SpawnChild("SimpleChildProcess"));
806 process.InitializePriority();
807 const std::string unique_token = process.unique_token();
808 ASSERT_FALSE(unique_token.empty());
809
810 EXPECT_TRUE(process.SetPriority(Process::Priority::kBestEffort));
811 EXPECT_EQ(process.GetPriority(), Process::Priority::kBestEffort);
812
813 // Create a stale cgroup
814 std::string root = kFullRendererCgroupRoot;
815 std::string cgroup = root + "/" + unique_token;
816 std::vector<std::string> tokens = base::SplitString(
817 cgroup, "-", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
818 tokens[1] = "fake";
819 std::string fake_cgroup = base::JoinString(tokens, "-");
820 EXPECT_TRUE(base::CreateDirectory(FilePath(fake_cgroup)));
821
822 // Clean up stale groups
823 Process::CleanUpStaleProcessStates();
824
825 // validate the fake group is deleted
826 EXPECT_FALSE(base::DirectoryExists(FilePath(fake_cgroup)));
827
828 // validate the active process cgroup is not deleted
829 EXPECT_TRUE(base::DirectoryExists(FilePath(cgroup)));
830
831 // validate foreground and background are not deleted
832 EXPECT_TRUE(base::DirectoryExists(FilePath(root + "/foreground")));
833 EXPECT_TRUE(base::DirectoryExists(FilePath(root + "/background")));
834
835 // clean up the process
836 EXPECT_TRUE(process.Terminate(0, false));
837 // Terminate should post a task, wait for it to run
838 task_env.RunUntilIdle();
839 EXPECT_FALSE(base::DirectoryExists(FilePath(cgroup)));
840 }
841
TEST_F(ProcessTest,OneCgroupDoesNotCleanUpGroupsWithWrongPrefix)842 TEST_F(ProcessTest, OneCgroupDoesNotCleanUpGroupsWithWrongPrefix) {
843 if (!Process::OneGroupPerRendererEnabledForTesting())
844 return;
845
846 base::test::TaskEnvironment task_env;
847
848 // Create a process that will not be cleaned up
849 Process process(SpawnChild("SimpleChildProcess"));
850 process.InitializePriority();
851 const std::string unique_token = process.unique_token();
852 ASSERT_FALSE(unique_token.empty());
853
854 EXPECT_TRUE(process.SetPriority(Process::Priority::kUserBlocking));
855 EXPECT_EQ(process.GetPriority(), Process::Priority::kUserBlocking);
856 std::string cgroup = GetProcessCpuCgroup(process);
857 EXPECT_FALSE(cgroup.empty());
858 EXPECT_NE(cgroup.find(unique_token), std::string::npos);
859
860 // Create a stale cgroup
861 FilePath cgroup_path = FilePath(std::string(kCgroupRoot) + cgroup);
862 FilePath fake_cgroup = FilePath(kFullRendererCgroupRoot).AppendASCII("fake");
863 EXPECT_TRUE(base::CreateDirectory(fake_cgroup));
864
865 // Clean up stale groups
866 Process::CleanUpStaleProcessStates();
867
868 // validate the fake group is deleted
869 EXPECT_TRUE(base::DirectoryExists(fake_cgroup));
870 EXPECT_TRUE(base::DirectoryExists(cgroup_path));
871
872 // clean up the process
873 EXPECT_TRUE(process.SetPriority(Process::Priority::kBestEffort));
874 EXPECT_EQ(process.GetPriority(), Process::Priority::kBestEffort);
875 EXPECT_TRUE(process.Terminate(0, false));
876 task_env.RunUntilIdle();
877 EXPECT_FALSE(base::DirectoryExists(cgroup_path));
878 base::DeleteFile(fake_cgroup);
879 }
880 #endif // BUILDFLAG(IS_CHROMEOS)
881
882 } // namespace base
883