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