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