1*6777b538SAndroid Build Coastguard Worker // Copyright 2011 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "base/process/process.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <errno.h>
8*6777b538SAndroid Build Coastguard Worker #include <linux/magic.h>
9*6777b538SAndroid Build Coastguard Worker #include <sys/resource.h>
10*6777b538SAndroid Build Coastguard Worker #include <sys/vfs.h>
11*6777b538SAndroid Build Coastguard Worker
12*6777b538SAndroid Build Coastguard Worker #include <cstring>
13*6777b538SAndroid Build Coastguard Worker #include <string_view>
14*6777b538SAndroid Build Coastguard Worker
15*6777b538SAndroid Build Coastguard Worker #include "base/check.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/files/file_util.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/location.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/notreached.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/posix/can_lower_nice_to.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/process/internal_linux.h"
22*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
23*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_split.h"
24*6777b538SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
25*6777b538SAndroid Build Coastguard Worker #include "base/threading/platform_thread.h"
26*6777b538SAndroid Build Coastguard Worker #include "base/threading/platform_thread_internal_posix.h"
27*6777b538SAndroid Build Coastguard Worker #include "base/threading/thread_restrictions.h"
28*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
29*6777b538SAndroid Build Coastguard Worker #include "build/chromeos_buildflags.h"
30*6777b538SAndroid Build Coastguard Worker
31*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS)
32*6777b538SAndroid Build Coastguard Worker #include "base/feature_list.h"
33*6777b538SAndroid Build Coastguard Worker #include "base/files/file_enumerator.h"
34*6777b538SAndroid Build Coastguard Worker #include "base/files/file_path.h"
35*6777b538SAndroid Build Coastguard Worker #include "base/functional/bind.h"
36*6777b538SAndroid Build Coastguard Worker #include "base/process/process_handle.h"
37*6777b538SAndroid Build Coastguard Worker #include "base/process/process_priority_delegate.h"
38*6777b538SAndroid Build Coastguard Worker #include "base/strings/strcat.h"
39*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
40*6777b538SAndroid Build Coastguard Worker #include "base/task/thread_pool.h"
41*6777b538SAndroid Build Coastguard Worker #include "base/unguessable_token.h"
42*6777b538SAndroid Build Coastguard Worker #endif // BUILDFLAG(IS_CHROMEOS)
43*6777b538SAndroid Build Coastguard Worker
44*6777b538SAndroid Build Coastguard Worker namespace base {
45*6777b538SAndroid Build Coastguard Worker
46*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS)
47*6777b538SAndroid Build Coastguard Worker BASE_FEATURE(kOneGroupPerRenderer,
48*6777b538SAndroid Build Coastguard Worker "OneGroupPerRenderer",
49*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS_LACROS)
50*6777b538SAndroid Build Coastguard Worker FEATURE_ENABLED_BY_DEFAULT);
51*6777b538SAndroid Build Coastguard Worker #else
52*6777b538SAndroid Build Coastguard Worker FEATURE_DISABLED_BY_DEFAULT);
53*6777b538SAndroid Build Coastguard Worker #endif // BUILDFLAG(IS_CHROMEOS_LACROS)
54*6777b538SAndroid Build Coastguard Worker #endif // BUILDFLAG(IS_CHROMEOS)
55*6777b538SAndroid Build Coastguard Worker
56*6777b538SAndroid Build Coastguard Worker namespace {
57*6777b538SAndroid Build Coastguard Worker
58*6777b538SAndroid Build Coastguard Worker const int kForegroundPriority = 0;
59*6777b538SAndroid Build Coastguard Worker
60*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS)
61*6777b538SAndroid Build Coastguard Worker ProcessPriorityDelegate* g_process_priority_delegate = nullptr;
62*6777b538SAndroid Build Coastguard Worker
63*6777b538SAndroid Build Coastguard Worker // We are more aggressive in our lowering of background process priority
64*6777b538SAndroid Build Coastguard Worker // for chromeos as we have much more control over other processes running
65*6777b538SAndroid Build Coastguard Worker // on the machine.
66*6777b538SAndroid Build Coastguard Worker //
67*6777b538SAndroid Build Coastguard Worker // TODO(davemoore) Refactor this by adding support for higher levels to set
68*6777b538SAndroid Build Coastguard Worker // the foregrounding / backgrounding process so we don't have to keep
69*6777b538SAndroid Build Coastguard Worker // chrome / chromeos specific logic here.
70*6777b538SAndroid Build Coastguard Worker const int kBackgroundPriority = 19;
71*6777b538SAndroid Build Coastguard Worker const char kControlPath[] = "/sys/fs/cgroup/cpu%s/cgroup.procs";
72*6777b538SAndroid Build Coastguard Worker const char kFullRendererCgroupRoot[] = "/sys/fs/cgroup/cpu/chrome_renderers";
73*6777b538SAndroid Build Coastguard Worker const char kForeground[] = "/chrome_renderers/foreground";
74*6777b538SAndroid Build Coastguard Worker const char kBackground[] = "/chrome_renderers/background";
75*6777b538SAndroid Build Coastguard Worker const char kProcPath[] = "/proc/%d/cgroup";
76*6777b538SAndroid Build Coastguard Worker const char kUclampMinFile[] = "cpu.uclamp.min";
77*6777b538SAndroid Build Coastguard Worker const char kUclampMaxFile[] = "cpu.uclamp.max";
78*6777b538SAndroid Build Coastguard Worker
79*6777b538SAndroid Build Coastguard Worker constexpr int kCgroupDeleteRetries = 3;
80*6777b538SAndroid Build Coastguard Worker constexpr TimeDelta kCgroupDeleteRetryTime(Seconds(1));
81*6777b538SAndroid Build Coastguard Worker
82*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS_LACROS)
83*6777b538SAndroid Build Coastguard Worker const char kCgroupPrefix[] = "l-";
84*6777b538SAndroid Build Coastguard Worker #elif BUILDFLAG(IS_CHROMEOS_ASH)
85*6777b538SAndroid Build Coastguard Worker const char kCgroupPrefix[] = "a-";
86*6777b538SAndroid Build Coastguard Worker #endif
87*6777b538SAndroid Build Coastguard Worker
PathIsCGroupFileSystem(const FilePath & path)88*6777b538SAndroid Build Coastguard Worker bool PathIsCGroupFileSystem(const FilePath& path) {
89*6777b538SAndroid Build Coastguard Worker struct statfs statfs_buf;
90*6777b538SAndroid Build Coastguard Worker if (statfs(path.value().c_str(), &statfs_buf) < 0)
91*6777b538SAndroid Build Coastguard Worker return false;
92*6777b538SAndroid Build Coastguard Worker return statfs_buf.f_type == CGROUP_SUPER_MAGIC;
93*6777b538SAndroid Build Coastguard Worker }
94*6777b538SAndroid Build Coastguard Worker
95*6777b538SAndroid Build Coastguard Worker struct CGroups {
96*6777b538SAndroid Build Coastguard Worker // Check for cgroups files. ChromeOS supports these by default. It creates
97*6777b538SAndroid Build Coastguard Worker // a cgroup mount in /sys/fs/cgroup and then configures two cpu task groups,
98*6777b538SAndroid Build Coastguard Worker // one contains at most a single foreground renderer and the other contains
99*6777b538SAndroid Build Coastguard Worker // all background renderers. This allows us to limit the impact of background
100*6777b538SAndroid Build Coastguard Worker // renderers on foreground ones to a greater level than simple renicing.
101*6777b538SAndroid Build Coastguard Worker bool enabled;
102*6777b538SAndroid Build Coastguard Worker FilePath foreground_file;
103*6777b538SAndroid Build Coastguard Worker FilePath background_file;
104*6777b538SAndroid Build Coastguard Worker
105*6777b538SAndroid Build Coastguard Worker // A unique token for this instance of the browser.
106*6777b538SAndroid Build Coastguard Worker std::string group_prefix_token;
107*6777b538SAndroid Build Coastguard Worker
108*6777b538SAndroid Build Coastguard Worker // UCLAMP settings for the foreground cgroups.
109*6777b538SAndroid Build Coastguard Worker std::string uclamp_min;
110*6777b538SAndroid Build Coastguard Worker std::string uclamp_max;
111*6777b538SAndroid Build Coastguard Worker
CGroupsbase::__anon617b259b0111::CGroups112*6777b538SAndroid Build Coastguard Worker CGroups() {
113*6777b538SAndroid Build Coastguard Worker foreground_file = FilePath(StringPrintf(kControlPath, kForeground));
114*6777b538SAndroid Build Coastguard Worker background_file = FilePath(StringPrintf(kControlPath, kBackground));
115*6777b538SAndroid Build Coastguard Worker enabled = PathIsCGroupFileSystem(foreground_file) &&
116*6777b538SAndroid Build Coastguard Worker PathIsCGroupFileSystem(background_file);
117*6777b538SAndroid Build Coastguard Worker
118*6777b538SAndroid Build Coastguard Worker if (!enabled || !FeatureList::IsEnabled(kOneGroupPerRenderer)) {
119*6777b538SAndroid Build Coastguard Worker return;
120*6777b538SAndroid Build Coastguard Worker }
121*6777b538SAndroid Build Coastguard Worker
122*6777b538SAndroid Build Coastguard Worker // Generate a unique token for the full browser process
123*6777b538SAndroid Build Coastguard Worker group_prefix_token =
124*6777b538SAndroid Build Coastguard Worker StrCat({kCgroupPrefix, UnguessableToken::Create().ToString(), "-"});
125*6777b538SAndroid Build Coastguard Worker
126*6777b538SAndroid Build Coastguard Worker // Reads the ULCAMP settings from the foreground cgroup that will be used
127*6777b538SAndroid Build Coastguard Worker // for each renderer's cgroup.
128*6777b538SAndroid Build Coastguard Worker FilePath foreground_path = foreground_file.DirName();
129*6777b538SAndroid Build Coastguard Worker ReadFileToString(foreground_path.Append(kUclampMinFile), &uclamp_min);
130*6777b538SAndroid Build Coastguard Worker ReadFileToString(foreground_path.Append(kUclampMaxFile), &uclamp_max);
131*6777b538SAndroid Build Coastguard Worker }
132*6777b538SAndroid Build Coastguard Worker
133*6777b538SAndroid Build Coastguard Worker // Returns the full path to a the cgroup dir of a process using
134*6777b538SAndroid Build Coastguard Worker // the supplied token.
GetForegroundCgroupDirbase::__anon617b259b0111::CGroups135*6777b538SAndroid Build Coastguard Worker static FilePath GetForegroundCgroupDir(const std::string& token) {
136*6777b538SAndroid Build Coastguard Worker // Get individualized cgroup if the feature is enabled
137*6777b538SAndroid Build Coastguard Worker std::string cgroup_path_str;
138*6777b538SAndroid Build Coastguard Worker StrAppend(&cgroup_path_str, {kFullRendererCgroupRoot, "/", token});
139*6777b538SAndroid Build Coastguard Worker return FilePath(cgroup_path_str);
140*6777b538SAndroid Build Coastguard Worker }
141*6777b538SAndroid Build Coastguard Worker
142*6777b538SAndroid Build Coastguard Worker // Returns the path to the cgroup.procs file of the foreground cgroup.
GetForegroundCgroupFilebase::__anon617b259b0111::CGroups143*6777b538SAndroid Build Coastguard Worker static FilePath GetForegroundCgroupFile(const std::string& token) {
144*6777b538SAndroid Build Coastguard Worker // Processes with an empty token use the default foreground cgroup.
145*6777b538SAndroid Build Coastguard Worker if (token.empty()) {
146*6777b538SAndroid Build Coastguard Worker return CGroups::Get().foreground_file;
147*6777b538SAndroid Build Coastguard Worker }
148*6777b538SAndroid Build Coastguard Worker
149*6777b538SAndroid Build Coastguard Worker FilePath cgroup_path = GetForegroundCgroupDir(token);
150*6777b538SAndroid Build Coastguard Worker return cgroup_path.Append("cgroup.procs");
151*6777b538SAndroid Build Coastguard Worker }
152*6777b538SAndroid Build Coastguard Worker
Getbase::__anon617b259b0111::CGroups153*6777b538SAndroid Build Coastguard Worker static CGroups& Get() {
154*6777b538SAndroid Build Coastguard Worker static auto& groups = *new CGroups;
155*6777b538SAndroid Build Coastguard Worker return groups;
156*6777b538SAndroid Build Coastguard Worker }
157*6777b538SAndroid Build Coastguard Worker };
158*6777b538SAndroid Build Coastguard Worker
159*6777b538SAndroid Build Coastguard Worker // Returns true if the 'OneGroupPerRenderer' feature is enabled. The feature
160*6777b538SAndroid Build Coastguard Worker // is enabled if the kOneGroupPerRenderer feature flag is enabled and the
161*6777b538SAndroid Build Coastguard Worker // system supports the chrome cgroups. Will block if this is the first call
162*6777b538SAndroid Build Coastguard Worker // that will read the cgroup configs.
OneGroupPerRendererEnabled()163*6777b538SAndroid Build Coastguard Worker bool OneGroupPerRendererEnabled() {
164*6777b538SAndroid Build Coastguard Worker return FeatureList::IsEnabled(kOneGroupPerRenderer) && CGroups::Get().enabled;
165*6777b538SAndroid Build Coastguard Worker }
166*6777b538SAndroid Build Coastguard Worker #else
167*6777b538SAndroid Build Coastguard Worker const int kBackgroundPriority = 5;
168*6777b538SAndroid Build Coastguard Worker #endif // BUILDFLAG(IS_CHROMEOS)
169*6777b538SAndroid Build Coastguard Worker
170*6777b538SAndroid Build Coastguard Worker } // namespace
171*6777b538SAndroid Build Coastguard Worker
CreationTime() const172*6777b538SAndroid Build Coastguard Worker Time Process::CreationTime() const {
173*6777b538SAndroid Build Coastguard Worker int64_t start_ticks = is_current()
174*6777b538SAndroid Build Coastguard Worker ? internal::ReadProcSelfStatsAndGetFieldAsInt64(
175*6777b538SAndroid Build Coastguard Worker internal::VM_STARTTIME)
176*6777b538SAndroid Build Coastguard Worker : internal::ReadProcStatsAndGetFieldAsInt64(
177*6777b538SAndroid Build Coastguard Worker Pid(), internal::VM_STARTTIME);
178*6777b538SAndroid Build Coastguard Worker
179*6777b538SAndroid Build Coastguard Worker if (!start_ticks)
180*6777b538SAndroid Build Coastguard Worker return Time();
181*6777b538SAndroid Build Coastguard Worker
182*6777b538SAndroid Build Coastguard Worker TimeDelta start_offset = internal::ClockTicksToTimeDelta(start_ticks);
183*6777b538SAndroid Build Coastguard Worker Time boot_time = internal::GetBootTime();
184*6777b538SAndroid Build Coastguard Worker if (boot_time.is_null())
185*6777b538SAndroid Build Coastguard Worker return Time();
186*6777b538SAndroid Build Coastguard Worker return Time(boot_time + start_offset);
187*6777b538SAndroid Build Coastguard Worker }
188*6777b538SAndroid Build Coastguard Worker
189*6777b538SAndroid Build Coastguard Worker // static
CanSetPriority()190*6777b538SAndroid Build Coastguard Worker bool Process::CanSetPriority() {
191*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS)
192*6777b538SAndroid Build Coastguard Worker if (g_process_priority_delegate) {
193*6777b538SAndroid Build Coastguard Worker return g_process_priority_delegate->CanSetProcessPriority();
194*6777b538SAndroid Build Coastguard Worker }
195*6777b538SAndroid Build Coastguard Worker
196*6777b538SAndroid Build Coastguard Worker if (CGroups::Get().enabled)
197*6777b538SAndroid Build Coastguard Worker return true;
198*6777b538SAndroid Build Coastguard Worker #endif // BUILDFLAG(IS_CHROMEOS)
199*6777b538SAndroid Build Coastguard Worker
200*6777b538SAndroid Build Coastguard Worker static const bool can_reraise_priority =
201*6777b538SAndroid Build Coastguard Worker internal::CanLowerNiceTo(kForegroundPriority);
202*6777b538SAndroid Build Coastguard Worker return can_reraise_priority;
203*6777b538SAndroid Build Coastguard Worker }
204*6777b538SAndroid Build Coastguard Worker
GetPriority() const205*6777b538SAndroid Build Coastguard Worker Process::Priority Process::GetPriority() const {
206*6777b538SAndroid Build Coastguard Worker DCHECK(IsValid());
207*6777b538SAndroid Build Coastguard Worker
208*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS)
209*6777b538SAndroid Build Coastguard Worker if (g_process_priority_delegate) {
210*6777b538SAndroid Build Coastguard Worker return g_process_priority_delegate->GetProcessPriority(process_);
211*6777b538SAndroid Build Coastguard Worker }
212*6777b538SAndroid Build Coastguard Worker
213*6777b538SAndroid Build Coastguard Worker if (CGroups::Get().enabled) {
214*6777b538SAndroid Build Coastguard Worker // Used to allow reading the process priority from proc on thread launch.
215*6777b538SAndroid Build Coastguard Worker ScopedAllowBlocking scoped_allow_blocking;
216*6777b538SAndroid Build Coastguard Worker std::string proc;
217*6777b538SAndroid Build Coastguard Worker if (ReadFileToString(FilePath(StringPrintf(kProcPath, process_)), &proc)) {
218*6777b538SAndroid Build Coastguard Worker return GetProcessPriorityCGroup(proc);
219*6777b538SAndroid Build Coastguard Worker }
220*6777b538SAndroid Build Coastguard Worker return Priority::kUserBlocking;
221*6777b538SAndroid Build Coastguard Worker }
222*6777b538SAndroid Build Coastguard Worker #endif // BUILDFLAG(IS_CHROMEOS)
223*6777b538SAndroid Build Coastguard Worker
224*6777b538SAndroid Build Coastguard Worker return GetOSPriority() == kBackgroundPriority ? Priority::kBestEffort
225*6777b538SAndroid Build Coastguard Worker : Priority::kUserBlocking;
226*6777b538SAndroid Build Coastguard Worker }
227*6777b538SAndroid Build Coastguard Worker
SetPriority(Priority priority)228*6777b538SAndroid Build Coastguard Worker bool Process::SetPriority(Priority priority) {
229*6777b538SAndroid Build Coastguard Worker DCHECK(IsValid());
230*6777b538SAndroid Build Coastguard Worker
231*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS)
232*6777b538SAndroid Build Coastguard Worker if (g_process_priority_delegate) {
233*6777b538SAndroid Build Coastguard Worker return g_process_priority_delegate->SetProcessPriority(process_, priority);
234*6777b538SAndroid Build Coastguard Worker }
235*6777b538SAndroid Build Coastguard Worker
236*6777b538SAndroid Build Coastguard Worker // Go through all the threads for a process and set it as [un]backgrounded.
237*6777b538SAndroid Build Coastguard Worker // Threads that are created after this call will also be [un]backgrounded by
238*6777b538SAndroid Build Coastguard Worker // detecting that the main thread of the process has been [un]backgrounded.
239*6777b538SAndroid Build Coastguard Worker
240*6777b538SAndroid Build Coastguard Worker // Should not be called concurrently with other functions
241*6777b538SAndroid Build Coastguard Worker // like SetThreadType().
242*6777b538SAndroid Build Coastguard Worker if (PlatformThreadChromeOS::IsThreadsBgFeatureEnabled()) {
243*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(
244*6777b538SAndroid Build Coastguard Worker PlatformThreadChromeOS::GetCrossProcessThreadPrioritySequenceChecker());
245*6777b538SAndroid Build Coastguard Worker
246*6777b538SAndroid Build Coastguard Worker int process_id = process_;
247*6777b538SAndroid Build Coastguard Worker bool background = priority == Priority::kBestEffort;
248*6777b538SAndroid Build Coastguard Worker internal::ForEachProcessTask(
249*6777b538SAndroid Build Coastguard Worker process_,
250*6777b538SAndroid Build Coastguard Worker [process_id, background](PlatformThreadId tid, const FilePath& path) {
251*6777b538SAndroid Build Coastguard Worker PlatformThreadChromeOS::SetThreadBackgrounded(process_id, tid,
252*6777b538SAndroid Build Coastguard Worker background);
253*6777b538SAndroid Build Coastguard Worker });
254*6777b538SAndroid Build Coastguard Worker }
255*6777b538SAndroid Build Coastguard Worker
256*6777b538SAndroid Build Coastguard Worker if (CGroups::Get().enabled) {
257*6777b538SAndroid Build Coastguard Worker std::string pid = NumberToString(process_);
258*6777b538SAndroid Build Coastguard Worker const FilePath file =
259*6777b538SAndroid Build Coastguard Worker priority == Priority::kBestEffort
260*6777b538SAndroid Build Coastguard Worker ? CGroups::Get().background_file
261*6777b538SAndroid Build Coastguard Worker : CGroups::Get().GetForegroundCgroupFile(unique_token_);
262*6777b538SAndroid Build Coastguard Worker return WriteFile(file, pid);
263*6777b538SAndroid Build Coastguard Worker }
264*6777b538SAndroid Build Coastguard Worker #endif // BUILDFLAG(IS_CHROMEOS)
265*6777b538SAndroid Build Coastguard Worker
266*6777b538SAndroid Build Coastguard Worker if (!CanSetPriority()) {
267*6777b538SAndroid Build Coastguard Worker return false;
268*6777b538SAndroid Build Coastguard Worker }
269*6777b538SAndroid Build Coastguard Worker
270*6777b538SAndroid Build Coastguard Worker int priority_value = priority == Priority::kBestEffort ? kBackgroundPriority
271*6777b538SAndroid Build Coastguard Worker : kForegroundPriority;
272*6777b538SAndroid Build Coastguard Worker int result =
273*6777b538SAndroid Build Coastguard Worker setpriority(PRIO_PROCESS, static_cast<id_t>(process_), priority_value);
274*6777b538SAndroid Build Coastguard Worker DPCHECK(result == 0);
275*6777b538SAndroid Build Coastguard Worker return result == 0;
276*6777b538SAndroid Build Coastguard Worker }
277*6777b538SAndroid Build Coastguard Worker
278*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS)
GetProcessPriorityCGroup(std::string_view cgroup_contents)279*6777b538SAndroid Build Coastguard Worker Process::Priority GetProcessPriorityCGroup(std::string_view cgroup_contents) {
280*6777b538SAndroid Build Coastguard Worker // The process can be part of multiple control groups, and for each cgroup
281*6777b538SAndroid Build Coastguard Worker // hierarchy there's an entry in the file. We look for a control group
282*6777b538SAndroid Build Coastguard Worker // named "/chrome_renderers/background" to determine if the process is
283*6777b538SAndroid Build Coastguard Worker // backgrounded. crbug.com/548818.
284*6777b538SAndroid Build Coastguard Worker std::vector<std::string_view> lines = SplitStringPiece(
285*6777b538SAndroid Build Coastguard Worker cgroup_contents, "\n", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
286*6777b538SAndroid Build Coastguard Worker for (const auto& line : lines) {
287*6777b538SAndroid Build Coastguard Worker std::vector<std::string_view> fields =
288*6777b538SAndroid Build Coastguard Worker SplitStringPiece(line, ":", TRIM_WHITESPACE, SPLIT_WANT_ALL);
289*6777b538SAndroid Build Coastguard Worker if (fields.size() != 3U) {
290*6777b538SAndroid Build Coastguard Worker NOTREACHED();
291*6777b538SAndroid Build Coastguard Worker continue;
292*6777b538SAndroid Build Coastguard Worker }
293*6777b538SAndroid Build Coastguard Worker if (fields[2] == kBackground)
294*6777b538SAndroid Build Coastguard Worker return Process::Priority::kBestEffort;
295*6777b538SAndroid Build Coastguard Worker }
296*6777b538SAndroid Build Coastguard Worker
297*6777b538SAndroid Build Coastguard Worker return Process::Priority::kUserBlocking;
298*6777b538SAndroid Build Coastguard Worker }
299*6777b538SAndroid Build Coastguard Worker #endif // BUILDFLAG(IS_CHROMEOS)
300*6777b538SAndroid Build Coastguard Worker
301*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS_ASH)
302*6777b538SAndroid Build Coastguard Worker // Reads /proc/<pid>/status and returns the PID in its PID namespace.
303*6777b538SAndroid Build Coastguard Worker // If the process is not in a PID namespace or /proc/<pid>/status does not
304*6777b538SAndroid Build Coastguard Worker // report NSpid, kNullProcessId is returned.
GetPidInNamespace() const305*6777b538SAndroid Build Coastguard Worker ProcessId Process::GetPidInNamespace() const {
306*6777b538SAndroid Build Coastguard Worker StringPairs pairs;
307*6777b538SAndroid Build Coastguard Worker if (!internal::ReadProcFileToTrimmedStringPairs(process_, "status", &pairs)) {
308*6777b538SAndroid Build Coastguard Worker return kNullProcessId;
309*6777b538SAndroid Build Coastguard Worker }
310*6777b538SAndroid Build Coastguard Worker for (const auto& pair : pairs) {
311*6777b538SAndroid Build Coastguard Worker const std::string& key = pair.first;
312*6777b538SAndroid Build Coastguard Worker const std::string& value_str = pair.second;
313*6777b538SAndroid Build Coastguard Worker if (key == "NSpid") {
314*6777b538SAndroid Build Coastguard Worker std::vector<std::string_view> split_value_str = SplitStringPiece(
315*6777b538SAndroid Build Coastguard Worker value_str, "\t", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
316*6777b538SAndroid Build Coastguard Worker if (split_value_str.size() <= 1) {
317*6777b538SAndroid Build Coastguard Worker return kNullProcessId;
318*6777b538SAndroid Build Coastguard Worker }
319*6777b538SAndroid Build Coastguard Worker int value;
320*6777b538SAndroid Build Coastguard Worker // The last value in the list is the PID in the namespace.
321*6777b538SAndroid Build Coastguard Worker if (!StringToInt(split_value_str.back(), &value)) {
322*6777b538SAndroid Build Coastguard Worker NOTREACHED();
323*6777b538SAndroid Build Coastguard Worker return kNullProcessId;
324*6777b538SAndroid Build Coastguard Worker }
325*6777b538SAndroid Build Coastguard Worker return value;
326*6777b538SAndroid Build Coastguard Worker }
327*6777b538SAndroid Build Coastguard Worker }
328*6777b538SAndroid Build Coastguard Worker return kNullProcessId;
329*6777b538SAndroid Build Coastguard Worker }
330*6777b538SAndroid Build Coastguard Worker #endif // BUILDFLAG(IS_CHROMEOS_ASH)
331*6777b538SAndroid Build Coastguard Worker
332*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
IsSeccompSandboxed()333*6777b538SAndroid Build Coastguard Worker bool Process::IsSeccompSandboxed() {
334*6777b538SAndroid Build Coastguard Worker uint64_t seccomp_value = 0;
335*6777b538SAndroid Build Coastguard Worker if (!internal::ReadProcStatusAndGetFieldAsUint64(process_, "Seccomp",
336*6777b538SAndroid Build Coastguard Worker &seccomp_value)) {
337*6777b538SAndroid Build Coastguard Worker return false;
338*6777b538SAndroid Build Coastguard Worker }
339*6777b538SAndroid Build Coastguard Worker return seccomp_value > 0;
340*6777b538SAndroid Build Coastguard Worker }
341*6777b538SAndroid Build Coastguard Worker #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
342*6777b538SAndroid Build Coastguard Worker
343*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS)
344*6777b538SAndroid Build Coastguard Worker // static
SetProcessPriorityDelegate(ProcessPriorityDelegate * delegate)345*6777b538SAndroid Build Coastguard Worker void Process::SetProcessPriorityDelegate(ProcessPriorityDelegate* delegate) {
346*6777b538SAndroid Build Coastguard Worker // A component cannot override a delegate set by another component, thus
347*6777b538SAndroid Build Coastguard Worker // disallow setting a delegate when one already exists.
348*6777b538SAndroid Build Coastguard Worker DCHECK_NE(!!g_process_priority_delegate, !!delegate);
349*6777b538SAndroid Build Coastguard Worker
350*6777b538SAndroid Build Coastguard Worker g_process_priority_delegate = delegate;
351*6777b538SAndroid Build Coastguard Worker }
352*6777b538SAndroid Build Coastguard Worker
353*6777b538SAndroid Build Coastguard Worker // static
OneGroupPerRendererEnabledForTesting()354*6777b538SAndroid Build Coastguard Worker bool Process::OneGroupPerRendererEnabledForTesting() {
355*6777b538SAndroid Build Coastguard Worker return OneGroupPerRendererEnabled();
356*6777b538SAndroid Build Coastguard Worker }
357*6777b538SAndroid Build Coastguard Worker
InitializePriority()358*6777b538SAndroid Build Coastguard Worker void Process::InitializePriority() {
359*6777b538SAndroid Build Coastguard Worker if (g_process_priority_delegate) {
360*6777b538SAndroid Build Coastguard Worker g_process_priority_delegate->InitializeProcessPriority(process_);
361*6777b538SAndroid Build Coastguard Worker return;
362*6777b538SAndroid Build Coastguard Worker }
363*6777b538SAndroid Build Coastguard Worker
364*6777b538SAndroid Build Coastguard Worker if (!OneGroupPerRendererEnabled() || !IsValid() || !unique_token_.empty()) {
365*6777b538SAndroid Build Coastguard Worker return;
366*6777b538SAndroid Build Coastguard Worker }
367*6777b538SAndroid Build Coastguard Worker // On Chrome OS, each renderer runs in its own cgroup when running in the
368*6777b538SAndroid Build Coastguard Worker // foreground. After process creation the cgroup is created using a
369*6777b538SAndroid Build Coastguard Worker // unique token.
370*6777b538SAndroid Build Coastguard Worker
371*6777b538SAndroid Build Coastguard Worker // The token has the following format:
372*6777b538SAndroid Build Coastguard Worker // {cgroup_prefix}{UnguessableToken}
373*6777b538SAndroid Build Coastguard Worker // The cgroup prefix is to distinguish ash from lacros tokens for stale
374*6777b538SAndroid Build Coastguard Worker // cgroup cleanup.
375*6777b538SAndroid Build Coastguard Worker unique_token_ = StrCat({CGroups::Get().group_prefix_token,
376*6777b538SAndroid Build Coastguard Worker UnguessableToken::Create().ToString()});
377*6777b538SAndroid Build Coastguard Worker
378*6777b538SAndroid Build Coastguard Worker FilePath cgroup_path = CGroups::Get().GetForegroundCgroupDir(unique_token_);
379*6777b538SAndroid Build Coastguard Worker // Note that CreateDirectoryAndGetError() does not fail if the directory
380*6777b538SAndroid Build Coastguard Worker // already exits.
381*6777b538SAndroid Build Coastguard Worker if (!CreateDirectoryAndGetError(cgroup_path, nullptr)) {
382*6777b538SAndroid Build Coastguard Worker // If creating the directory fails, fall back to use the foreground group.
383*6777b538SAndroid Build Coastguard Worker int saved_errno = errno;
384*6777b538SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to create cgroup, falling back to foreground"
385*6777b538SAndroid Build Coastguard Worker << ", cgroup=" << cgroup_path
386*6777b538SAndroid Build Coastguard Worker << ", errno=" << strerror(saved_errno);
387*6777b538SAndroid Build Coastguard Worker
388*6777b538SAndroid Build Coastguard Worker unique_token_.clear();
389*6777b538SAndroid Build Coastguard Worker return;
390*6777b538SAndroid Build Coastguard Worker }
391*6777b538SAndroid Build Coastguard Worker
392*6777b538SAndroid Build Coastguard Worker if (!CGroups::Get().uclamp_min.empty() &&
393*6777b538SAndroid Build Coastguard Worker !WriteFile(cgroup_path.Append(kUclampMinFile),
394*6777b538SAndroid Build Coastguard Worker CGroups::Get().uclamp_min)) {
395*6777b538SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to write uclamp min file, cgroup_path="
396*6777b538SAndroid Build Coastguard Worker << cgroup_path;
397*6777b538SAndroid Build Coastguard Worker }
398*6777b538SAndroid Build Coastguard Worker if (!CGroups::Get().uclamp_min.empty() &&
399*6777b538SAndroid Build Coastguard Worker !WriteFile(cgroup_path.Append(kUclampMaxFile),
400*6777b538SAndroid Build Coastguard Worker CGroups::Get().uclamp_max)) {
401*6777b538SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to write uclamp max file, cgroup_path="
402*6777b538SAndroid Build Coastguard Worker << cgroup_path;
403*6777b538SAndroid Build Coastguard Worker }
404*6777b538SAndroid Build Coastguard Worker }
405*6777b538SAndroid Build Coastguard Worker
ForgetPriority()406*6777b538SAndroid Build Coastguard Worker void Process::ForgetPriority() {
407*6777b538SAndroid Build Coastguard Worker if (g_process_priority_delegate) {
408*6777b538SAndroid Build Coastguard Worker g_process_priority_delegate->ForgetProcessPriority(process_);
409*6777b538SAndroid Build Coastguard Worker return;
410*6777b538SAndroid Build Coastguard Worker }
411*6777b538SAndroid Build Coastguard Worker }
412*6777b538SAndroid Build Coastguard Worker
413*6777b538SAndroid Build Coastguard Worker // static
CleanUpProcessScheduled(Process process,int remaining_retries)414*6777b538SAndroid Build Coastguard Worker void Process::CleanUpProcessScheduled(Process process, int remaining_retries) {
415*6777b538SAndroid Build Coastguard Worker process.CleanUpProcess(remaining_retries);
416*6777b538SAndroid Build Coastguard Worker }
417*6777b538SAndroid Build Coastguard Worker
CleanUpProcessAsync() const418*6777b538SAndroid Build Coastguard Worker void Process::CleanUpProcessAsync() const {
419*6777b538SAndroid Build Coastguard Worker if (!FeatureList::IsEnabled(kOneGroupPerRenderer) || unique_token_.empty()) {
420*6777b538SAndroid Build Coastguard Worker return;
421*6777b538SAndroid Build Coastguard Worker }
422*6777b538SAndroid Build Coastguard Worker
423*6777b538SAndroid Build Coastguard Worker ThreadPool::PostTask(FROM_HERE, {MayBlock(), TaskPriority::BEST_EFFORT},
424*6777b538SAndroid Build Coastguard Worker BindOnce(&Process::CleanUpProcessScheduled, Duplicate(),
425*6777b538SAndroid Build Coastguard Worker kCgroupDeleteRetries));
426*6777b538SAndroid Build Coastguard Worker }
427*6777b538SAndroid Build Coastguard Worker
CleanUpProcess(int remaining_retries) const428*6777b538SAndroid Build Coastguard Worker void Process::CleanUpProcess(int remaining_retries) const {
429*6777b538SAndroid Build Coastguard Worker if (!OneGroupPerRendererEnabled() || unique_token_.empty()) {
430*6777b538SAndroid Build Coastguard Worker return;
431*6777b538SAndroid Build Coastguard Worker }
432*6777b538SAndroid Build Coastguard Worker
433*6777b538SAndroid Build Coastguard Worker // Try to delete the cgroup
434*6777b538SAndroid Build Coastguard Worker // TODO(1322562): We can use notify_on_release to automoatically delete the
435*6777b538SAndroid Build Coastguard Worker // cgroup when the process has left the cgroup.
436*6777b538SAndroid Build Coastguard Worker FilePath cgroup = CGroups::Get().GetForegroundCgroupDir(unique_token_);
437*6777b538SAndroid Build Coastguard Worker if (!DeleteFile(cgroup)) {
438*6777b538SAndroid Build Coastguard Worker auto saved_errno = errno;
439*6777b538SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to delete cgroup " << cgroup
440*6777b538SAndroid Build Coastguard Worker << ", errno=" << strerror(saved_errno);
441*6777b538SAndroid Build Coastguard Worker // If the delete failed, then the process is still potentially in the
442*6777b538SAndroid Build Coastguard Worker // cgroup. Move the process to background and schedule a callback to try
443*6777b538SAndroid Build Coastguard Worker // again.
444*6777b538SAndroid Build Coastguard Worker if (remaining_retries > 0) {
445*6777b538SAndroid Build Coastguard Worker std::string pidstr = NumberToString(process_);
446*6777b538SAndroid Build Coastguard Worker if (!WriteFile(CGroups::Get().background_file, pidstr)) {
447*6777b538SAndroid Build Coastguard Worker // Failed to move the process, LOG a warning but try again.
448*6777b538SAndroid Build Coastguard Worker saved_errno = errno;
449*6777b538SAndroid Build Coastguard Worker LOG(WARNING) << "Failed to move the process to background"
450*6777b538SAndroid Build Coastguard Worker << ", pid=" << pidstr
451*6777b538SAndroid Build Coastguard Worker << ", errno=" << strerror(saved_errno);
452*6777b538SAndroid Build Coastguard Worker }
453*6777b538SAndroid Build Coastguard Worker ThreadPool::PostDelayedTask(FROM_HERE,
454*6777b538SAndroid Build Coastguard Worker {MayBlock(), TaskPriority::BEST_EFFORT},
455*6777b538SAndroid Build Coastguard Worker BindOnce(&Process::CleanUpProcessScheduled,
456*6777b538SAndroid Build Coastguard Worker Duplicate(), remaining_retries - 1),
457*6777b538SAndroid Build Coastguard Worker kCgroupDeleteRetryTime);
458*6777b538SAndroid Build Coastguard Worker }
459*6777b538SAndroid Build Coastguard Worker }
460*6777b538SAndroid Build Coastguard Worker }
461*6777b538SAndroid Build Coastguard Worker
462*6777b538SAndroid Build Coastguard Worker // static
CleanUpStaleProcessStates()463*6777b538SAndroid Build Coastguard Worker void Process::CleanUpStaleProcessStates() {
464*6777b538SAndroid Build Coastguard Worker if (!OneGroupPerRendererEnabled()) {
465*6777b538SAndroid Build Coastguard Worker return;
466*6777b538SAndroid Build Coastguard Worker }
467*6777b538SAndroid Build Coastguard Worker
468*6777b538SAndroid Build Coastguard Worker FileEnumerator traversal(FilePath(kFullRendererCgroupRoot), false,
469*6777b538SAndroid Build Coastguard Worker FileEnumerator::DIRECTORIES);
470*6777b538SAndroid Build Coastguard Worker for (FilePath path = traversal.Next(); !path.empty();
471*6777b538SAndroid Build Coastguard Worker path = traversal.Next()) {
472*6777b538SAndroid Build Coastguard Worker std::string dirname = path.BaseName().value();
473*6777b538SAndroid Build Coastguard Worker if (dirname == FilePath(kForeground).BaseName().value() ||
474*6777b538SAndroid Build Coastguard Worker dirname == FilePath(kBackground).BaseName().value()) {
475*6777b538SAndroid Build Coastguard Worker continue;
476*6777b538SAndroid Build Coastguard Worker }
477*6777b538SAndroid Build Coastguard Worker
478*6777b538SAndroid Build Coastguard Worker if (!StartsWith(dirname, kCgroupPrefix) ||
479*6777b538SAndroid Build Coastguard Worker StartsWith(dirname, CGroups::Get().group_prefix_token)) {
480*6777b538SAndroid Build Coastguard Worker continue;
481*6777b538SAndroid Build Coastguard Worker }
482*6777b538SAndroid Build Coastguard Worker
483*6777b538SAndroid Build Coastguard Worker if (!DeleteFile(path)) {
484*6777b538SAndroid Build Coastguard Worker auto saved_errno = errno;
485*6777b538SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to delete " << path
486*6777b538SAndroid Build Coastguard Worker << ", errno=" << strerror(saved_errno);
487*6777b538SAndroid Build Coastguard Worker }
488*6777b538SAndroid Build Coastguard Worker }
489*6777b538SAndroid Build Coastguard Worker }
490*6777b538SAndroid Build Coastguard Worker #endif // BUILDFLAG(IS_CHROMEOS)
491*6777b538SAndroid Build Coastguard Worker
492*6777b538SAndroid Build Coastguard Worker } // namespace base
493