Thanks to visit codestin.com
Credit goes to chromium.googlesource.com

blob: e0f95584b772f83aed41ce5db33f36e1d6f9d85c [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2011 The Chromium Authors
[email protected]276aa6a2009-10-29 17:43:442// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]76bea672013-07-19 16:48:565#include "base/process/process.h"
[email protected]276aa6a2009-10-29 17:43:446
7#include <errno.h>
Elly Fong-Jones44835da2022-11-03 23:35:288#include <linux/magic.h>
[email protected]276aa6a2009-10-29 17:43:449#include <sys/resource.h>
Elly Fong-Jones44835da2022-11-03 23:35:2810#include <sys/vfs.h>
[email protected]276aa6a2009-10-29 17:43:4411
Youssef Esmatc732bf82022-05-27 00:47:1912#include <cstring>
Joe Mason484bfa52025-05-16 21:14:4013#include <optional>
14#include <string>
Helmut Januschkabfa62f72024-04-04 15:18:3115#include <string_view>
Youssef Esmatc732bf82022-05-27 00:47:1916
Hans Wennborgc3cffa62020-04-27 10:09:1217#include "base/check.h"
[email protected]e3177dd52014-08-13 20:22:1418#include "base/files/file_util.h"
Youssef Esmatc732bf82022-05-27 00:47:1919#include "base/location.h"
20#include "base/logging.h"
Hans Wennborgc3cffa62020-04-27 10:09:1221#include "base/notreached.h"
Francois Doray48171e2a2018-09-13 16:19:4022#include "base/posix/can_lower_nice_to.h"
Francois Doray7d1315342018-10-21 03:54:4723#include "base/process/internal_linux.h"
riceaa01edead2015-07-01 15:56:5024#include "base/strings/string_number_conversions.h"
[email protected]5ae0b763e2013-02-07 23:01:3925#include "base/strings/string_split.h"
[email protected]d1a5a2f2013-06-10 21:17:4026#include "base/strings/stringprintf.h"
Joel Fernandesf3f294f2023-09-22 17:29:4527#include "base/threading/platform_thread.h"
28#include "base/threading/platform_thread_internal_posix.h"
nyad2c548b2015-12-09 03:22:3229#include "base/threading/thread_restrictions.h"
avibeced7c2015-12-24 06:47:5930#include "build/build_config.h"
[email protected]3e55e212011-03-24 19:45:0231
Youssef Esmatc732bf82022-05-27 00:47:1932#if BUILDFLAG(IS_CHROMEOS)
Youssef Esmatc732bf82022-05-27 00:47:1933#include "base/feature_list.h"
34#include "base/files/file_enumerator.h"
35#include "base/files/file_path.h"
Avi Drissman63e1f992023-01-13 18:54:4336#include "base/functional/bind.h"
Shintaro Kawamuradb0ae3e2024-12-26 07:41:3337#include "base/metrics/field_trial_params.h"
Youssef Esmatc732bf82022-05-27 00:47:1938#include "base/process/process_handle.h"
Shintaro Kawamuraf29c8fdf2024-03-28 03:40:0839#include "base/process/process_priority_delegate.h"
Youssef Esmatc732bf82022-05-27 00:47:1940#include "base/strings/strcat.h"
41#include "base/strings/string_util.h"
42#include "base/task/thread_pool.h"
43#include "base/unguessable_token.h"
44#endif // BUILDFLAG(IS_CHROMEOS)
45
[email protected]a26f4ae2014-03-13 17:26:2146namespace base {
47
Youssef Esmatc732bf82022-05-27 00:47:1948#if BUILDFLAG(IS_CHROMEOS)
Xiaohan Wang019c1152025-09-09 05:11:2049BASE_FEATURE(kOneGroupPerRenderer, FEATURE_DISABLED_BY_DEFAULT);
Shintaro Kawamuradb0ae3e2024-12-26 07:41:3350
Xiaohan Wang019c1152025-09-09 05:11:2051BASE_FEATURE(kFlattenCpuCgroups, FEATURE_ENABLED_BY_DEFAULT);
Shintaro Kawamuradb0ae3e2024-12-26 07:41:3352
53// If FlattenCpuCgroupsUnified parameter is enabled, foreground renderer
54// processes uses /sys/fs/cgroup/cpu/ui cgroup instead of
55// /sys/fs/cgroup/cpu/chrome_renderers sharing the cpu cgroup with the browser
56// process and others.
57BASE_FEATURE_PARAM(bool,
58 kFlattenCpuCgroupsUnified,
59 &kFlattenCpuCgroups,
60 "unified_cpu_cgroup",
61 false);
Youssef Esmatc732bf82022-05-27 00:47:1962#endif // BUILDFLAG(IS_CHROMEOS)
63
[email protected]8a420802011-12-02 16:14:4664namespace {
rvargas079d1842014-10-17 22:32:1665
[email protected]8a420802011-12-02 16:14:4666const int kForegroundPriority = 0;
[email protected]276aa6a2009-10-29 17:43:4467
Eric Willigers611cf54e2022-04-28 02:22:1468#if BUILDFLAG(IS_CHROMEOS)
Shintaro Kawamuraf29c8fdf2024-03-28 03:40:0869ProcessPriorityDelegate* g_process_priority_delegate = nullptr;
70
[email protected]4d641082011-02-09 21:27:2871// We are more aggressive in our lowering of background process priority
72// for chromeos as we have much more control over other processes running
73// on the machine.
[email protected]8a420802011-12-02 16:14:4674//
75// TODO(davemoore) Refactor this by adding support for higher levels to set
76// the foregrounding / backgrounding process so we don't have to keep
77// chrome / chromeos specific logic here.
78const int kBackgroundPriority = 19;
[email protected]f9b950e2013-01-26 03:48:3879const char kControlPath[] = "/sys/fs/cgroup/cpu%s/cgroup.procs";
Youssef Esmatc732bf82022-05-27 00:47:1980const char kFullRendererCgroupRoot[] = "/sys/fs/cgroup/cpu/chrome_renderers";
[email protected]8a420802011-12-02 16:14:4681const char kForeground[] = "/chrome_renderers/foreground";
82const char kBackground[] = "/chrome_renderers/background";
Shintaro Kawamuradb0ae3e2024-12-26 07:41:3383const char kForegroundExperiment[] = "/chrome_renderers";
84const char kForegroundUnifiedExperiment[] = "/ui";
85const char kBackgroundExperiment[] = "/chrome_renderers_background";
[email protected]8a420802011-12-02 16:14:4686const char kProcPath[] = "/proc/%d/cgroup";
Youssef Esmatc732bf82022-05-27 00:47:1987const char kUclampMinFile[] = "cpu.uclamp.min";
88const char kUclampMaxFile[] = "cpu.uclamp.max";
89
90constexpr int kCgroupDeleteRetries = 3;
91constexpr TimeDelta kCgroupDeleteRetryTime(Seconds(1));
92
Youssef Esmatc732bf82022-05-27 00:47:1993const char kCgroupPrefix[] = "a-";
[email protected]8a420802011-12-02 16:14:4694
Elly Fong-Jones44835da2022-11-03 23:35:2895bool PathIsCGroupFileSystem(const FilePath& path) {
96 struct statfs statfs_buf;
Peter Kasting134ef9af2024-12-28 02:30:0997 if (statfs(path.value().c_str(), &statfs_buf) < 0) {
Elly Fong-Jones44835da2022-11-03 23:35:2898 return false;
Peter Kasting134ef9af2024-12-28 02:30:0999 }
Elly Fong-Jones44835da2022-11-03 23:35:28100 return statfs_buf.f_type == CGROUP_SUPER_MAGIC;
101}
102
[email protected]8a420802011-12-02 16:14:46103struct CGroups {
104 // Check for cgroups files. ChromeOS supports these by default. It creates
[email protected]f9b950e2013-01-26 03:48:38105 // a cgroup mount in /sys/fs/cgroup and then configures two cpu task groups,
[email protected]8a420802011-12-02 16:14:46106 // one contains at most a single foreground renderer and the other contains
107 // all background renderers. This allows us to limit the impact of background
108 // renderers on foreground ones to a greater level than simple renicing.
109 bool enabled;
Youssef Esmatc732bf82022-05-27 00:47:19110 FilePath foreground_file;
111 FilePath background_file;
112
113 // A unique token for this instance of the browser.
114 std::string group_prefix_token;
115
116 // UCLAMP settings for the foreground cgroups.
117 std::string uclamp_min;
118 std::string uclamp_max;
[email protected]8a420802011-12-02 16:14:46119
120 CGroups() {
Shintaro Kawamuradb0ae3e2024-12-26 07:41:33121 if (FeatureList::IsEnabled(kFlattenCpuCgroups)) {
122 foreground_file =
123 FilePath(StringPrintf(kControlPath, kFlattenCpuCgroupsUnified.Get()
124 ? kForegroundUnifiedExperiment
125 : kForegroundExperiment));
126 background_file =
127 FilePath(StringPrintf(kControlPath, kBackgroundExperiment));
128 } else {
129 foreground_file = FilePath(StringPrintf(kControlPath, kForeground));
130 background_file = FilePath(StringPrintf(kControlPath, kBackground));
131 }
Elly Fong-Jones44835da2022-11-03 23:35:28132 enabled = PathIsCGroupFileSystem(foreground_file) &&
133 PathIsCGroupFileSystem(background_file);
Youssef Esmatc732bf82022-05-27 00:47:19134
135 if (!enabled || !FeatureList::IsEnabled(kOneGroupPerRenderer)) {
136 return;
137 }
138
139 // Generate a unique token for the full browser process
140 group_prefix_token =
141 StrCat({kCgroupPrefix, UnguessableToken::Create().ToString(), "-"});
142
143 // Reads the ULCAMP settings from the foreground cgroup that will be used
144 // for each renderer's cgroup.
145 FilePath foreground_path = foreground_file.DirName();
146 ReadFileToString(foreground_path.Append(kUclampMinFile), &uclamp_min);
147 ReadFileToString(foreground_path.Append(kUclampMaxFile), &uclamp_max);
148 }
149
150 // Returns the full path to a the cgroup dir of a process using
151 // the supplied token.
152 static FilePath GetForegroundCgroupDir(const std::string& token) {
153 // Get individualized cgroup if the feature is enabled
154 std::string cgroup_path_str;
155 StrAppend(&cgroup_path_str, {kFullRendererCgroupRoot, "/", token});
156 return FilePath(cgroup_path_str);
157 }
158
159 // Returns the path to the cgroup.procs file of the foreground cgroup.
160 static FilePath GetForegroundCgroupFile(const std::string& token) {
161 // Processes with an empty token use the default foreground cgroup.
162 if (token.empty()) {
163 return CGroups::Get().foreground_file;
164 }
165
166 FilePath cgroup_path = GetForegroundCgroupDir(token);
167 return cgroup_path.Append("cgroup.procs");
[email protected]8a420802011-12-02 16:14:46168 }
[email protected]8a420802011-12-02 16:14:46169
danakj6c77b2f2017-03-10 16:40:25170 static CGroups& Get() {
171 static auto& groups = *new CGroups;
172 return groups;
173 }
174};
Youssef Esmatc732bf82022-05-27 00:47:19175
Youssef Esmat10aa75d2022-06-10 11:58:46176// Returns true if the 'OneGroupPerRenderer' feature is enabled. The feature
177// is enabled if the kOneGroupPerRenderer feature flag is enabled and the
178// system supports the chrome cgroups. Will block if this is the first call
179// that will read the cgroup configs.
180bool OneGroupPerRendererEnabled() {
181 return FeatureList::IsEnabled(kOneGroupPerRenderer) && CGroups::Get().enabled;
182}
[email protected]4d641082011-02-09 21:27:28183#else
[email protected]8a420802011-12-02 16:14:46184const int kBackgroundPriority = 5;
Eric Willigers611cf54e2022-04-28 02:22:14185#endif // BUILDFLAG(IS_CHROMEOS)
rvargas079d1842014-10-17 22:32:16186
rvargas079d1842014-10-17 22:32:16187} // namespace
188
Francois Doray7d1315342018-10-21 03:54:47189Time Process::CreationTime() const {
190 int64_t start_ticks = is_current()
191 ? internal::ReadProcSelfStatsAndGetFieldAsInt64(
192 internal::VM_STARTTIME)
193 : internal::ReadProcStatsAndGetFieldAsInt64(
194 Pid(), internal::VM_STARTTIME);
Benoit Lize8a544692020-08-31 15:43:42195
Peter Kasting134ef9af2024-12-28 02:30:09196 if (!start_ticks) {
Francois Doray7d1315342018-10-21 03:54:47197 return Time();
Peter Kasting134ef9af2024-12-28 02:30:09198 }
Benoit Lize8a544692020-08-31 15:43:42199
Francois Doray7d1315342018-10-21 03:54:47200 TimeDelta start_offset = internal::ClockTicksToTimeDelta(start_ticks);
201 Time boot_time = internal::GetBootTime();
Peter Kasting134ef9af2024-12-28 02:30:09202 if (boot_time.is_null()) {
Francois Doray7d1315342018-10-21 03:54:47203 return Time();
Peter Kasting134ef9af2024-12-28 02:30:09204 }
Francois Doray7d1315342018-10-21 03:54:47205 return Time(boot_time + start_offset);
206}
207
rvargas079d1842014-10-17 22:32:16208// static
Patrick Monette5d1ba7ca32023-08-02 22:05:27209bool Process::CanSetPriority() {
Eric Willigers611cf54e2022-04-28 02:22:14210#if BUILDFLAG(IS_CHROMEOS)
Shintaro Kawamuraf29c8fdf2024-03-28 03:40:08211 if (g_process_priority_delegate) {
212 return g_process_priority_delegate->CanSetProcessPriority();
213 }
214
Peter Kasting134ef9af2024-12-28 02:30:09215 if (CGroups::Get().enabled) {
rvargas079d1842014-10-17 22:32:16216 return true;
Peter Kasting134ef9af2024-12-28 02:30:09217 }
Eric Willigers611cf54e2022-04-28 02:22:14218#endif // BUILDFLAG(IS_CHROMEOS)
rvargas079d1842014-10-17 22:32:16219
Francois Doray48171e2a2018-09-13 16:19:40220 static const bool can_reraise_priority =
221 internal::CanLowerNiceTo(kForegroundPriority);
Francois Dorayc4b34ec2018-04-23 19:37:51222 return can_reraise_priority;
[email protected]8a420802011-12-02 16:14:46223}
224
Patrick Monette5d1ba7ca32023-08-02 22:05:27225Process::Priority Process::GetPriority() const {
rvargas079d1842014-10-17 22:32:16226 DCHECK(IsValid());
[email protected]8a420802011-12-02 16:14:46227
Eric Willigers611cf54e2022-04-28 02:22:14228#if BUILDFLAG(IS_CHROMEOS)
Shintaro Kawamuraf726c1292024-03-28 03:40:08229 if (g_process_priority_delegate) {
230 return g_process_priority_delegate->GetProcessPriority(process_);
231 }
232
danakj6c77b2f2017-03-10 16:40:25233 if (CGroups::Get().enabled) {
sebsgcbde0672015-10-16 20:18:47234 // Used to allow reading the process priority from proc on thread launch.
Etienne Pierre-dorayd5b86d22022-11-07 18:05:50235 ScopedAllowBlocking scoped_allow_blocking;
[email protected]8a420802011-12-02 16:14:46236 std::string proc;
Youssef Esmatc732bf82022-05-27 00:47:19237 if (ReadFileToString(FilePath(StringPrintf(kProcPath, process_)), &proc)) {
Patrick Monette5d1ba7ca32023-08-02 22:05:27238 return GetProcessPriorityCGroup(proc);
[email protected]8a420802011-12-02 16:14:46239 }
Patrick Monette5d1ba7ca32023-08-02 22:05:27240 return Priority::kUserBlocking;
[email protected]8a420802011-12-02 16:14:46241 }
Eric Willigers611cf54e2022-04-28 02:22:14242#endif // BUILDFLAG(IS_CHROMEOS)
afakhry8b4796b2015-11-16 18:41:44243
Patrick Monette5d1ba7ca32023-08-02 22:05:27244 return GetOSPriority() == kBackgroundPriority ? Priority::kBestEffort
245 : Priority::kUserBlocking;
[email protected]276aa6a2009-10-29 17:43:44246}
247
Patrick Monette5d1ba7ca32023-08-02 22:05:27248bool Process::SetPriority(Priority priority) {
rvargas079d1842014-10-17 22:32:16249 DCHECK(IsValid());
[email protected]276aa6a2009-10-29 17:43:44250
Eric Willigers611cf54e2022-04-28 02:22:14251#if BUILDFLAG(IS_CHROMEOS)
Shintaro Kawamuraf29c8fdf2024-03-28 03:40:08252 if (g_process_priority_delegate) {
253 return g_process_priority_delegate->SetProcessPriority(process_, priority);
254 }
255
Joel Fernandesf3f294f2023-09-22 17:29:45256 // Go through all the threads for a process and set it as [un]backgrounded.
257 // Threads that are created after this call will also be [un]backgrounded by
258 // detecting that the main thread of the process has been [un]backgrounded.
259
260 // Should not be called concurrently with other functions
261 // like SetThreadType().
262 if (PlatformThreadChromeOS::IsThreadsBgFeatureEnabled()) {
Peter Kasting6f90c017b2024-12-03 01:07:29263 PlatformThreadChromeOS::DcheckCrossProcessThreadPrioritySequence();
Joel Fernandesf3f294f2023-09-22 17:29:45264
265 int process_id = process_;
266 bool background = priority == Priority::kBestEffort;
267 internal::ForEachProcessTask(
268 process_,
269 [process_id, background](PlatformThreadId tid, const FilePath& path) {
270 PlatformThreadChromeOS::SetThreadBackgrounded(process_id, tid,
271 background);
272 });
273 }
274
danakj6c77b2f2017-03-10 16:40:25275 if (CGroups::Get().enabled) {
Raul Tambrea9c13642019-03-25 13:34:42276 std::string pid = NumberToString(process_);
Youssef Esmatc732bf82022-05-27 00:47:19277 const FilePath file =
Patrick Monette5d1ba7ca32023-08-02 22:05:27278 priority == Priority::kBestEffort
279 ? CGroups::Get().background_file
280 : CGroups::Get().GetForegroundCgroupFile(unique_token_);
Youssef Esmatc732bf82022-05-27 00:47:19281 return WriteFile(file, pid);
[email protected]3e55e212011-03-24 19:45:02282 }
Eric Willigers611cf54e2022-04-28 02:22:14283#endif // BUILDFLAG(IS_CHROMEOS)
[email protected]3e55e212011-03-24 19:45:02284
Patrick Monette5d1ba7ca32023-08-02 22:05:27285 if (!CanSetPriority()) {
[email protected]8a420802011-12-02 16:14:46286 return false;
Patrick Monette5d1ba7ca32023-08-02 22:05:27287 }
[email protected]8a420802011-12-02 16:14:46288
Patrick Monette5d1ba7ca32023-08-02 22:05:27289 int priority_value = priority == Priority::kBestEffort ? kBackgroundPriority
290 : kForegroundPriority;
291 int result =
292 setpriority(PRIO_PROCESS, static_cast<id_t>(process_), priority_value);
[email protected]8a420802011-12-02 16:14:46293 DPCHECK(result == 0);
294 return result == 0;
295}
296
Eric Willigers611cf54e2022-04-28 02:22:14297#if BUILDFLAG(IS_CHROMEOS)
Helmut Januschkabfa62f72024-04-04 15:18:31298Process::Priority GetProcessPriorityCGroup(std::string_view cgroup_contents) {
afakhry8b4796b2015-11-16 18:41:44299 // The process can be part of multiple control groups, and for each cgroup
300 // hierarchy there's an entry in the file. We look for a control group
301 // named "/chrome_renderers/background" to determine if the process is
302 // backgrounded. crbug.com/548818.
Helmut Januschkabfa62f72024-04-04 15:18:31303 std::vector<std::string_view> lines = SplitStringPiece(
lhchavez99fbcf82015-11-24 17:54:32304 cgroup_contents, "\n", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
afakhry8b4796b2015-11-16 18:41:44305 for (const auto& line : lines) {
Helmut Januschkabfa62f72024-04-04 15:18:31306 std::vector<std::string_view> fields =
afakhry8b4796b2015-11-16 18:41:44307 SplitStringPiece(line, ":", TRIM_WHITESPACE, SPLIT_WANT_ALL);
308 if (fields.size() != 3U) {
Peter Boströmde573332024-08-26 20:42:45309 NOTREACHED();
afakhry8b4796b2015-11-16 18:41:44310 }
Shintaro Kawamurace38e972025-03-18 23:46:54311 if (fields[2] == kBackgroundExperiment || fields[2] == kBackground) {
Patrick Monette5d1ba7ca32023-08-02 22:05:27312 return Process::Priority::kBestEffort;
Peter Kasting134ef9af2024-12-28 02:30:09313 }
afakhry8b4796b2015-11-16 18:41:44314 }
315
Patrick Monette5d1ba7ca32023-08-02 22:05:27316 return Process::Priority::kUserBlocking;
afakhry8b4796b2015-11-16 18:41:44317}
afakhry8b4796b2015-11-16 18:41:44318
nyad2c548b2015-12-09 03:22:32319// Reads /proc/<pid>/status and returns the PID in its PID namespace.
320// If the process is not in a PID namespace or /proc/<pid>/status does not
321// report NSpid, kNullProcessId is returned.
322ProcessId Process::GetPidInNamespace() const {
Joe Mason484bfa52025-05-16 21:14:40323 std::string buffer;
324 std::optional<StringViewPairs> pairs =
325 internal::ReadProcFileToTrimmedStringPairs(process_, "status", &buffer);
326 if (!pairs) {
Matthew Dentonf969883422023-08-08 01:44:34327 return kNullProcessId;
328 }
Joe Mason484bfa52025-05-16 21:14:40329 for (const auto& [key, value_str] : *pairs) {
nyad2c548b2015-12-09 03:22:32330 if (key == "NSpid") {
Helmut Januschkabfa62f72024-04-04 15:18:31331 std::vector<std::string_view> split_value_str = SplitStringPiece(
nyad2c548b2015-12-09 03:22:32332 value_str, "\t", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
333 if (split_value_str.size() <= 1) {
334 return kNullProcessId;
335 }
336 int value;
337 // The last value in the list is the PID in the namespace.
338 if (!StringToInt(split_value_str.back(), &value)) {
Peter Boströmde573332024-08-26 20:42:45339 NOTREACHED();
nyad2c548b2015-12-09 03:22:32340 }
341 return value;
342 }
343 }
344 return kNullProcessId;
345}
Georg Neisff37fb52025-02-05 09:05:26346#endif // BUILDFLAG(IS_CHROMEOS)
nyad2c548b2015-12-09 03:22:32347
Matthew Dentonf969883422023-08-08 01:44:34348#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
349bool Process::IsSeccompSandboxed() {
350 uint64_t seccomp_value = 0;
351 if (!internal::ReadProcStatusAndGetFieldAsUint64(process_, "Seccomp",
352 &seccomp_value)) {
353 return false;
354 }
355 return seccomp_value > 0;
356}
357#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
358
Youssef Esmatc732bf82022-05-27 00:47:19359#if BUILDFLAG(IS_CHROMEOS)
360// static
Shintaro Kawamuraf29c8fdf2024-03-28 03:40:08361void Process::SetProcessPriorityDelegate(ProcessPriorityDelegate* delegate) {
362 // A component cannot override a delegate set by another component, thus
363 // disallow setting a delegate when one already exists.
364 DCHECK_NE(!!g_process_priority_delegate, !!delegate);
365
366 g_process_priority_delegate = delegate;
367}
368
369// static
Youssef Esmat10aa75d2022-06-10 11:58:46370bool Process::OneGroupPerRendererEnabledForTesting() {
371 return OneGroupPerRendererEnabled();
Youssef Esmatc732bf82022-05-27 00:47:19372}
373
Youssef Esmatc732bf82022-05-27 00:47:19374void Process::InitializePriority() {
Shintaro Kawamuraf726c1292024-03-28 03:40:08375 if (g_process_priority_delegate) {
376 g_process_priority_delegate->InitializeProcessPriority(process_);
377 return;
378 }
379
Youssef Esmatc732bf82022-05-27 00:47:19380 if (!OneGroupPerRendererEnabled() || !IsValid() || !unique_token_.empty()) {
381 return;
382 }
Shintaro Kawamuraf726c1292024-03-28 03:40:08383 // On Chrome OS, each renderer runs in its own cgroup when running in the
384 // foreground. After process creation the cgroup is created using a
385 // unique token.
Youssef Esmatc732bf82022-05-27 00:47:19386
387 // The token has the following format:
388 // {cgroup_prefix}{UnguessableToken}
389 // The cgroup prefix is to distinguish ash from lacros tokens for stale
390 // cgroup cleanup.
391 unique_token_ = StrCat({CGroups::Get().group_prefix_token,
392 UnguessableToken::Create().ToString()});
393
394 FilePath cgroup_path = CGroups::Get().GetForegroundCgroupDir(unique_token_);
395 // Note that CreateDirectoryAndGetError() does not fail if the directory
396 // already exits.
397 if (!CreateDirectoryAndGetError(cgroup_path, nullptr)) {
398 // If creating the directory fails, fall back to use the foreground group.
399 int saved_errno = errno;
400 LOG(ERROR) << "Failed to create cgroup, falling back to foreground"
401 << ", cgroup=" << cgroup_path
402 << ", errno=" << strerror(saved_errno);
403
404 unique_token_.clear();
405 return;
406 }
407
408 if (!CGroups::Get().uclamp_min.empty() &&
409 !WriteFile(cgroup_path.Append(kUclampMinFile),
410 CGroups::Get().uclamp_min)) {
411 LOG(ERROR) << "Failed to write uclamp min file, cgroup_path="
412 << cgroup_path;
413 }
414 if (!CGroups::Get().uclamp_min.empty() &&
415 !WriteFile(cgroup_path.Append(kUclampMaxFile),
416 CGroups::Get().uclamp_max)) {
417 LOG(ERROR) << "Failed to write uclamp max file, cgroup_path="
418 << cgroup_path;
419 }
420}
421
Shintaro Kawamuraf726c1292024-03-28 03:40:08422void Process::ForgetPriority() {
423 if (g_process_priority_delegate) {
424 g_process_priority_delegate->ForgetProcessPriority(process_);
425 return;
426 }
427}
428
Youssef Esmatc732bf82022-05-27 00:47:19429// static
430void Process::CleanUpProcessScheduled(Process process, int remaining_retries) {
431 process.CleanUpProcess(remaining_retries);
432}
433
434void Process::CleanUpProcessAsync() const {
Youssef Esmat10aa75d2022-06-10 11:58:46435 if (!FeatureList::IsEnabled(kOneGroupPerRenderer) || unique_token_.empty()) {
Youssef Esmatc732bf82022-05-27 00:47:19436 return;
437 }
438
439 ThreadPool::PostTask(FROM_HERE, {MayBlock(), TaskPriority::BEST_EFFORT},
440 BindOnce(&Process::CleanUpProcessScheduled, Duplicate(),
441 kCgroupDeleteRetries));
442}
443
444void Process::CleanUpProcess(int remaining_retries) const {
445 if (!OneGroupPerRendererEnabled() || unique_token_.empty()) {
446 return;
447 }
448
449 // Try to delete the cgroup
Alison Gale81f4f2c72024-04-22 19:33:31450 // TODO(crbug.com/40224348): We can use notify_on_release to automoatically
451 // delete the cgroup when the process has left the cgroup.
Youssef Esmatc732bf82022-05-27 00:47:19452 FilePath cgroup = CGroups::Get().GetForegroundCgroupDir(unique_token_);
453 if (!DeleteFile(cgroup)) {
454 auto saved_errno = errno;
455 LOG(ERROR) << "Failed to delete cgroup " << cgroup
456 << ", errno=" << strerror(saved_errno);
457 // If the delete failed, then the process is still potentially in the
458 // cgroup. Move the process to background and schedule a callback to try
459 // again.
460 if (remaining_retries > 0) {
461 std::string pidstr = NumberToString(process_);
462 if (!WriteFile(CGroups::Get().background_file, pidstr)) {
463 // Failed to move the process, LOG a warning but try again.
464 saved_errno = errno;
465 LOG(WARNING) << "Failed to move the process to background"
466 << ", pid=" << pidstr
467 << ", errno=" << strerror(saved_errno);
468 }
469 ThreadPool::PostDelayedTask(FROM_HERE,
470 {MayBlock(), TaskPriority::BEST_EFFORT},
471 BindOnce(&Process::CleanUpProcessScheduled,
472 Duplicate(), remaining_retries - 1),
473 kCgroupDeleteRetryTime);
474 }
475 }
476}
477
478// static
479void Process::CleanUpStaleProcessStates() {
480 if (!OneGroupPerRendererEnabled()) {
481 return;
482 }
483
484 FileEnumerator traversal(FilePath(kFullRendererCgroupRoot), false,
485 FileEnumerator::DIRECTORIES);
486 for (FilePath path = traversal.Next(); !path.empty();
487 path = traversal.Next()) {
488 std::string dirname = path.BaseName().value();
489 if (dirname == FilePath(kForeground).BaseName().value() ||
490 dirname == FilePath(kBackground).BaseName().value()) {
491 continue;
492 }
493
494 if (!StartsWith(dirname, kCgroupPrefix) ||
495 StartsWith(dirname, CGroups::Get().group_prefix_token)) {
496 continue;
497 }
498
499 if (!DeleteFile(path)) {
500 auto saved_errno = errno;
501 LOG(ERROR) << "Failed to delete " << path
502 << ", errno=" << strerror(saved_errno);
503 }
504 }
505}
506#endif // BUILDFLAG(IS_CHROMEOS)
507
[email protected]276aa6a2009-10-29 17:43:44508} // namespace base