xref: /aosp_15_r20/external/cronet/base/process/process_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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