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