| Avi Drissman | e4622aa | 2022-09-08 20:36:06 | [diff] [blame] | 1 | // Copyright 2011 The Chromium Authors |
| [email protected] | 276aa6a | 2009-10-29 17:43:44 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| [email protected] | 76bea67 | 2013-07-19 16:48:56 | [diff] [blame] | 5 | #include "base/process/process.h" |
| [email protected] | 276aa6a | 2009-10-29 17:43:44 | [diff] [blame] | 6 | |
| 7 | #include <errno.h> |
| Elly Fong-Jones | 44835da | 2022-11-03 23:35:28 | [diff] [blame] | 8 | #include <linux/magic.h> |
| [email protected] | 276aa6a | 2009-10-29 17:43:44 | [diff] [blame] | 9 | #include <sys/resource.h> |
| Elly Fong-Jones | 44835da | 2022-11-03 23:35:28 | [diff] [blame] | 10 | #include <sys/vfs.h> |
| [email protected] | 276aa6a | 2009-10-29 17:43:44 | [diff] [blame] | 11 | |
| Youssef Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 12 | #include <cstring> |
| Joe Mason | 484bfa5 | 2025-05-16 21:14:40 | [diff] [blame] | 13 | #include <optional> |
| 14 | #include <string> |
| Helmut Januschka | bfa62f7 | 2024-04-04 15:18:31 | [diff] [blame] | 15 | #include <string_view> |
| Youssef Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 16 | |
| Hans Wennborg | c3cffa6 | 2020-04-27 10:09:12 | [diff] [blame] | 17 | #include "base/check.h" |
| [email protected] | e3177dd5 | 2014-08-13 20:22:14 | [diff] [blame] | 18 | #include "base/files/file_util.h" |
| Youssef Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 19 | #include "base/location.h" |
| 20 | #include "base/logging.h" |
| Hans Wennborg | c3cffa6 | 2020-04-27 10:09:12 | [diff] [blame] | 21 | #include "base/notreached.h" |
| Francois Doray | 48171e2a | 2018-09-13 16:19:40 | [diff] [blame] | 22 | #include "base/posix/can_lower_nice_to.h" |
| Francois Doray | 7d131534 | 2018-10-21 03:54:47 | [diff] [blame] | 23 | #include "base/process/internal_linux.h" |
| ricea | a01edead | 2015-07-01 15:56:50 | [diff] [blame] | 24 | #include "base/strings/string_number_conversions.h" |
| [email protected] | 5ae0b763e | 2013-02-07 23:01:39 | [diff] [blame] | 25 | #include "base/strings/string_split.h" |
| [email protected] | d1a5a2f | 2013-06-10 21:17:40 | [diff] [blame] | 26 | #include "base/strings/stringprintf.h" |
| Joel Fernandes | f3f294f | 2023-09-22 17:29:45 | [diff] [blame] | 27 | #include "base/threading/platform_thread.h" |
| 28 | #include "base/threading/platform_thread_internal_posix.h" |
| nya | d2c548b | 2015-12-09 03:22:32 | [diff] [blame] | 29 | #include "base/threading/thread_restrictions.h" |
| avi | beced7c | 2015-12-24 06:47:59 | [diff] [blame] | 30 | #include "build/build_config.h" |
| [email protected] | 3e55e21 | 2011-03-24 19:45:02 | [diff] [blame] | 31 | |
| Youssef Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 32 | #if BUILDFLAG(IS_CHROMEOS) |
| Youssef Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 33 | #include "base/feature_list.h" |
| 34 | #include "base/files/file_enumerator.h" |
| 35 | #include "base/files/file_path.h" |
| Avi Drissman | 63e1f99 | 2023-01-13 18:54:43 | [diff] [blame] | 36 | #include "base/functional/bind.h" |
| Shintaro Kawamura | db0ae3e | 2024-12-26 07:41:33 | [diff] [blame] | 37 | #include "base/metrics/field_trial_params.h" |
| Youssef Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 38 | #include "base/process/process_handle.h" |
| Shintaro Kawamura | f29c8fdf | 2024-03-28 03:40:08 | [diff] [blame] | 39 | #include "base/process/process_priority_delegate.h" |
| Youssef Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 40 | #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] | a26f4ae | 2014-03-13 17:26:21 | [diff] [blame] | 46 | namespace base { |
| 47 | |
| Youssef Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 48 | #if BUILDFLAG(IS_CHROMEOS) |
| Xiaohan Wang | 019c115 | 2025-09-09 05:11:20 | [diff] [blame] | 49 | BASE_FEATURE(kOneGroupPerRenderer, FEATURE_DISABLED_BY_DEFAULT); |
| Shintaro Kawamura | db0ae3e | 2024-12-26 07:41:33 | [diff] [blame] | 50 | |
| Xiaohan Wang | 019c115 | 2025-09-09 05:11:20 | [diff] [blame] | 51 | BASE_FEATURE(kFlattenCpuCgroups, FEATURE_ENABLED_BY_DEFAULT); |
| Shintaro Kawamura | db0ae3e | 2024-12-26 07:41:33 | [diff] [blame] | 52 | |
| 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. |
| 57 | BASE_FEATURE_PARAM(bool, |
| 58 | kFlattenCpuCgroupsUnified, |
| 59 | &kFlattenCpuCgroups, |
| 60 | "unified_cpu_cgroup", |
| 61 | false); |
| Youssef Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 62 | #endif // BUILDFLAG(IS_CHROMEOS) |
| 63 | |
| [email protected] | 8a42080 | 2011-12-02 16:14:46 | [diff] [blame] | 64 | namespace { |
| rvargas | 079d184 | 2014-10-17 22:32:16 | [diff] [blame] | 65 | |
| [email protected] | 8a42080 | 2011-12-02 16:14:46 | [diff] [blame] | 66 | const int kForegroundPriority = 0; |
| [email protected] | 276aa6a | 2009-10-29 17:43:44 | [diff] [blame] | 67 | |
| Eric Willigers | 611cf54e | 2022-04-28 02:22:14 | [diff] [blame] | 68 | #if BUILDFLAG(IS_CHROMEOS) |
| Shintaro Kawamura | f29c8fdf | 2024-03-28 03:40:08 | [diff] [blame] | 69 | ProcessPriorityDelegate* g_process_priority_delegate = nullptr; |
| 70 | |
| [email protected] | 4d64108 | 2011-02-09 21:27:28 | [diff] [blame] | 71 | // 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] | 8a42080 | 2011-12-02 16:14:46 | [diff] [blame] | 74 | // |
| 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. |
| 78 | const int kBackgroundPriority = 19; |
| [email protected] | f9b950e | 2013-01-26 03:48:38 | [diff] [blame] | 79 | const char kControlPath[] = "/sys/fs/cgroup/cpu%s/cgroup.procs"; |
| Youssef Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 80 | const char kFullRendererCgroupRoot[] = "/sys/fs/cgroup/cpu/chrome_renderers"; |
| [email protected] | 8a42080 | 2011-12-02 16:14:46 | [diff] [blame] | 81 | const char kForeground[] = "/chrome_renderers/foreground"; |
| 82 | const char kBackground[] = "/chrome_renderers/background"; |
| Shintaro Kawamura | db0ae3e | 2024-12-26 07:41:33 | [diff] [blame] | 83 | const char kForegroundExperiment[] = "/chrome_renderers"; |
| 84 | const char kForegroundUnifiedExperiment[] = "/ui"; |
| 85 | const char kBackgroundExperiment[] = "/chrome_renderers_background"; |
| [email protected] | 8a42080 | 2011-12-02 16:14:46 | [diff] [blame] | 86 | const char kProcPath[] = "/proc/%d/cgroup"; |
| Youssef Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 87 | const char kUclampMinFile[] = "cpu.uclamp.min"; |
| 88 | const char kUclampMaxFile[] = "cpu.uclamp.max"; |
| 89 | |
| 90 | constexpr int kCgroupDeleteRetries = 3; |
| 91 | constexpr TimeDelta kCgroupDeleteRetryTime(Seconds(1)); |
| 92 | |
| Youssef Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 93 | const char kCgroupPrefix[] = "a-"; |
| [email protected] | 8a42080 | 2011-12-02 16:14:46 | [diff] [blame] | 94 | |
| Elly Fong-Jones | 44835da | 2022-11-03 23:35:28 | [diff] [blame] | 95 | bool PathIsCGroupFileSystem(const FilePath& path) { |
| 96 | struct statfs statfs_buf; |
| Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 97 | if (statfs(path.value().c_str(), &statfs_buf) < 0) { |
| Elly Fong-Jones | 44835da | 2022-11-03 23:35:28 | [diff] [blame] | 98 | return false; |
| Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 99 | } |
| Elly Fong-Jones | 44835da | 2022-11-03 23:35:28 | [diff] [blame] | 100 | return statfs_buf.f_type == CGROUP_SUPER_MAGIC; |
| 101 | } |
| 102 | |
| [email protected] | 8a42080 | 2011-12-02 16:14:46 | [diff] [blame] | 103 | struct CGroups { |
| 104 | // Check for cgroups files. ChromeOS supports these by default. It creates |
| [email protected] | f9b950e | 2013-01-26 03:48:38 | [diff] [blame] | 105 | // a cgroup mount in /sys/fs/cgroup and then configures two cpu task groups, |
| [email protected] | 8a42080 | 2011-12-02 16:14:46 | [diff] [blame] | 106 | // 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 Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 110 | 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] | 8a42080 | 2011-12-02 16:14:46 | [diff] [blame] | 119 | |
| 120 | CGroups() { |
| Shintaro Kawamura | db0ae3e | 2024-12-26 07:41:33 | [diff] [blame] | 121 | 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-Jones | 44835da | 2022-11-03 23:35:28 | [diff] [blame] | 132 | enabled = PathIsCGroupFileSystem(foreground_file) && |
| 133 | PathIsCGroupFileSystem(background_file); |
| Youssef Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 134 | |
| 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] | 8a42080 | 2011-12-02 16:14:46 | [diff] [blame] | 168 | } |
| [email protected] | 8a42080 | 2011-12-02 16:14:46 | [diff] [blame] | 169 | |
| danakj | 6c77b2f | 2017-03-10 16:40:25 | [diff] [blame] | 170 | static CGroups& Get() { |
| 171 | static auto& groups = *new CGroups; |
| 172 | return groups; |
| 173 | } |
| 174 | }; |
| Youssef Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 175 | |
| Youssef Esmat | 10aa75d | 2022-06-10 11:58:46 | [diff] [blame] | 176 | // 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. |
| 180 | bool OneGroupPerRendererEnabled() { |
| 181 | return FeatureList::IsEnabled(kOneGroupPerRenderer) && CGroups::Get().enabled; |
| 182 | } |
| [email protected] | 4d64108 | 2011-02-09 21:27:28 | [diff] [blame] | 183 | #else |
| [email protected] | 8a42080 | 2011-12-02 16:14:46 | [diff] [blame] | 184 | const int kBackgroundPriority = 5; |
| Eric Willigers | 611cf54e | 2022-04-28 02:22:14 | [diff] [blame] | 185 | #endif // BUILDFLAG(IS_CHROMEOS) |
| rvargas | 079d184 | 2014-10-17 22:32:16 | [diff] [blame] | 186 | |
| rvargas | 079d184 | 2014-10-17 22:32:16 | [diff] [blame] | 187 | } // namespace |
| 188 | |
| Francois Doray | 7d131534 | 2018-10-21 03:54:47 | [diff] [blame] | 189 | Time 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 Lize | 8a54469 | 2020-08-31 15:43:42 | [diff] [blame] | 195 | |
| Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 196 | if (!start_ticks) { |
| Francois Doray | 7d131534 | 2018-10-21 03:54:47 | [diff] [blame] | 197 | return Time(); |
| Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 198 | } |
| Benoit Lize | 8a54469 | 2020-08-31 15:43:42 | [diff] [blame] | 199 | |
| Francois Doray | 7d131534 | 2018-10-21 03:54:47 | [diff] [blame] | 200 | TimeDelta start_offset = internal::ClockTicksToTimeDelta(start_ticks); |
| 201 | Time boot_time = internal::GetBootTime(); |
| Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 202 | if (boot_time.is_null()) { |
| Francois Doray | 7d131534 | 2018-10-21 03:54:47 | [diff] [blame] | 203 | return Time(); |
| Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 204 | } |
| Francois Doray | 7d131534 | 2018-10-21 03:54:47 | [diff] [blame] | 205 | return Time(boot_time + start_offset); |
| 206 | } |
| 207 | |
| rvargas | 079d184 | 2014-10-17 22:32:16 | [diff] [blame] | 208 | // static |
| Patrick Monette | 5d1ba7ca3 | 2023-08-02 22:05:27 | [diff] [blame] | 209 | bool Process::CanSetPriority() { |
| Eric Willigers | 611cf54e | 2022-04-28 02:22:14 | [diff] [blame] | 210 | #if BUILDFLAG(IS_CHROMEOS) |
| Shintaro Kawamura | f29c8fdf | 2024-03-28 03:40:08 | [diff] [blame] | 211 | if (g_process_priority_delegate) { |
| 212 | return g_process_priority_delegate->CanSetProcessPriority(); |
| 213 | } |
| 214 | |
| Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 215 | if (CGroups::Get().enabled) { |
| rvargas | 079d184 | 2014-10-17 22:32:16 | [diff] [blame] | 216 | return true; |
| Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 217 | } |
| Eric Willigers | 611cf54e | 2022-04-28 02:22:14 | [diff] [blame] | 218 | #endif // BUILDFLAG(IS_CHROMEOS) |
| rvargas | 079d184 | 2014-10-17 22:32:16 | [diff] [blame] | 219 | |
| Francois Doray | 48171e2a | 2018-09-13 16:19:40 | [diff] [blame] | 220 | static const bool can_reraise_priority = |
| 221 | internal::CanLowerNiceTo(kForegroundPriority); |
| Francois Doray | c4b34ec | 2018-04-23 19:37:51 | [diff] [blame] | 222 | return can_reraise_priority; |
| [email protected] | 8a42080 | 2011-12-02 16:14:46 | [diff] [blame] | 223 | } |
| 224 | |
| Patrick Monette | 5d1ba7ca3 | 2023-08-02 22:05:27 | [diff] [blame] | 225 | Process::Priority Process::GetPriority() const { |
| rvargas | 079d184 | 2014-10-17 22:32:16 | [diff] [blame] | 226 | DCHECK(IsValid()); |
| [email protected] | 8a42080 | 2011-12-02 16:14:46 | [diff] [blame] | 227 | |
| Eric Willigers | 611cf54e | 2022-04-28 02:22:14 | [diff] [blame] | 228 | #if BUILDFLAG(IS_CHROMEOS) |
| Shintaro Kawamura | f726c129 | 2024-03-28 03:40:08 | [diff] [blame] | 229 | if (g_process_priority_delegate) { |
| 230 | return g_process_priority_delegate->GetProcessPriority(process_); |
| 231 | } |
| 232 | |
| danakj | 6c77b2f | 2017-03-10 16:40:25 | [diff] [blame] | 233 | if (CGroups::Get().enabled) { |
| sebsg | cbde067 | 2015-10-16 20:18:47 | [diff] [blame] | 234 | // Used to allow reading the process priority from proc on thread launch. |
| Etienne Pierre-doray | d5b86d2 | 2022-11-07 18:05:50 | [diff] [blame] | 235 | ScopedAllowBlocking scoped_allow_blocking; |
| [email protected] | 8a42080 | 2011-12-02 16:14:46 | [diff] [blame] | 236 | std::string proc; |
| Youssef Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 237 | if (ReadFileToString(FilePath(StringPrintf(kProcPath, process_)), &proc)) { |
| Patrick Monette | 5d1ba7ca3 | 2023-08-02 22:05:27 | [diff] [blame] | 238 | return GetProcessPriorityCGroup(proc); |
| [email protected] | 8a42080 | 2011-12-02 16:14:46 | [diff] [blame] | 239 | } |
| Patrick Monette | 5d1ba7ca3 | 2023-08-02 22:05:27 | [diff] [blame] | 240 | return Priority::kUserBlocking; |
| [email protected] | 8a42080 | 2011-12-02 16:14:46 | [diff] [blame] | 241 | } |
| Eric Willigers | 611cf54e | 2022-04-28 02:22:14 | [diff] [blame] | 242 | #endif // BUILDFLAG(IS_CHROMEOS) |
| afakhry | 8b4796b | 2015-11-16 18:41:44 | [diff] [blame] | 243 | |
| Patrick Monette | 5d1ba7ca3 | 2023-08-02 22:05:27 | [diff] [blame] | 244 | return GetOSPriority() == kBackgroundPriority ? Priority::kBestEffort |
| 245 | : Priority::kUserBlocking; |
| [email protected] | 276aa6a | 2009-10-29 17:43:44 | [diff] [blame] | 246 | } |
| 247 | |
| Patrick Monette | 5d1ba7ca3 | 2023-08-02 22:05:27 | [diff] [blame] | 248 | bool Process::SetPriority(Priority priority) { |
| rvargas | 079d184 | 2014-10-17 22:32:16 | [diff] [blame] | 249 | DCHECK(IsValid()); |
| [email protected] | 276aa6a | 2009-10-29 17:43:44 | [diff] [blame] | 250 | |
| Eric Willigers | 611cf54e | 2022-04-28 02:22:14 | [diff] [blame] | 251 | #if BUILDFLAG(IS_CHROMEOS) |
| Shintaro Kawamura | f29c8fdf | 2024-03-28 03:40:08 | [diff] [blame] | 252 | if (g_process_priority_delegate) { |
| 253 | return g_process_priority_delegate->SetProcessPriority(process_, priority); |
| 254 | } |
| 255 | |
| Joel Fernandes | f3f294f | 2023-09-22 17:29:45 | [diff] [blame] | 256 | // 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 Kasting | 6f90c017b | 2024-12-03 01:07:29 | [diff] [blame] | 263 | PlatformThreadChromeOS::DcheckCrossProcessThreadPrioritySequence(); |
| Joel Fernandes | f3f294f | 2023-09-22 17:29:45 | [diff] [blame] | 264 | |
| 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 | |
| danakj | 6c77b2f | 2017-03-10 16:40:25 | [diff] [blame] | 275 | if (CGroups::Get().enabled) { |
| Raul Tambre | a9c1364 | 2019-03-25 13:34:42 | [diff] [blame] | 276 | std::string pid = NumberToString(process_); |
| Youssef Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 277 | const FilePath file = |
| Patrick Monette | 5d1ba7ca3 | 2023-08-02 22:05:27 | [diff] [blame] | 278 | priority == Priority::kBestEffort |
| 279 | ? CGroups::Get().background_file |
| 280 | : CGroups::Get().GetForegroundCgroupFile(unique_token_); |
| Youssef Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 281 | return WriteFile(file, pid); |
| [email protected] | 3e55e21 | 2011-03-24 19:45:02 | [diff] [blame] | 282 | } |
| Eric Willigers | 611cf54e | 2022-04-28 02:22:14 | [diff] [blame] | 283 | #endif // BUILDFLAG(IS_CHROMEOS) |
| [email protected] | 3e55e21 | 2011-03-24 19:45:02 | [diff] [blame] | 284 | |
| Patrick Monette | 5d1ba7ca3 | 2023-08-02 22:05:27 | [diff] [blame] | 285 | if (!CanSetPriority()) { |
| [email protected] | 8a42080 | 2011-12-02 16:14:46 | [diff] [blame] | 286 | return false; |
| Patrick Monette | 5d1ba7ca3 | 2023-08-02 22:05:27 | [diff] [blame] | 287 | } |
| [email protected] | 8a42080 | 2011-12-02 16:14:46 | [diff] [blame] | 288 | |
| Patrick Monette | 5d1ba7ca3 | 2023-08-02 22:05:27 | [diff] [blame] | 289 | 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] | 8a42080 | 2011-12-02 16:14:46 | [diff] [blame] | 293 | DPCHECK(result == 0); |
| 294 | return result == 0; |
| 295 | } |
| 296 | |
| Eric Willigers | 611cf54e | 2022-04-28 02:22:14 | [diff] [blame] | 297 | #if BUILDFLAG(IS_CHROMEOS) |
| Helmut Januschka | bfa62f7 | 2024-04-04 15:18:31 | [diff] [blame] | 298 | Process::Priority GetProcessPriorityCGroup(std::string_view cgroup_contents) { |
| afakhry | 8b4796b | 2015-11-16 18:41:44 | [diff] [blame] | 299 | // 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 Januschka | bfa62f7 | 2024-04-04 15:18:31 | [diff] [blame] | 303 | std::vector<std::string_view> lines = SplitStringPiece( |
| lhchavez | 99fbcf8 | 2015-11-24 17:54:32 | [diff] [blame] | 304 | cgroup_contents, "\n", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY); |
| afakhry | 8b4796b | 2015-11-16 18:41:44 | [diff] [blame] | 305 | for (const auto& line : lines) { |
| Helmut Januschka | bfa62f7 | 2024-04-04 15:18:31 | [diff] [blame] | 306 | std::vector<std::string_view> fields = |
| afakhry | 8b4796b | 2015-11-16 18:41:44 | [diff] [blame] | 307 | SplitStringPiece(line, ":", TRIM_WHITESPACE, SPLIT_WANT_ALL); |
| 308 | if (fields.size() != 3U) { |
| Peter Boström | de57333 | 2024-08-26 20:42:45 | [diff] [blame] | 309 | NOTREACHED(); |
| afakhry | 8b4796b | 2015-11-16 18:41:44 | [diff] [blame] | 310 | } |
| Shintaro Kawamura | ce38e97 | 2025-03-18 23:46:54 | [diff] [blame] | 311 | if (fields[2] == kBackgroundExperiment || fields[2] == kBackground) { |
| Patrick Monette | 5d1ba7ca3 | 2023-08-02 22:05:27 | [diff] [blame] | 312 | return Process::Priority::kBestEffort; |
| Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 313 | } |
| afakhry | 8b4796b | 2015-11-16 18:41:44 | [diff] [blame] | 314 | } |
| 315 | |
| Patrick Monette | 5d1ba7ca3 | 2023-08-02 22:05:27 | [diff] [blame] | 316 | return Process::Priority::kUserBlocking; |
| afakhry | 8b4796b | 2015-11-16 18:41:44 | [diff] [blame] | 317 | } |
| afakhry | 8b4796b | 2015-11-16 18:41:44 | [diff] [blame] | 318 | |
| nya | d2c548b | 2015-12-09 03:22:32 | [diff] [blame] | 319 | // 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. |
| 322 | ProcessId Process::GetPidInNamespace() const { |
| Joe Mason | 484bfa5 | 2025-05-16 21:14:40 | [diff] [blame] | 323 | std::string buffer; |
| 324 | std::optional<StringViewPairs> pairs = |
| 325 | internal::ReadProcFileToTrimmedStringPairs(process_, "status", &buffer); |
| 326 | if (!pairs) { |
| Matthew Denton | f96988342 | 2023-08-08 01:44:34 | [diff] [blame] | 327 | return kNullProcessId; |
| 328 | } |
| Joe Mason | 484bfa5 | 2025-05-16 21:14:40 | [diff] [blame] | 329 | for (const auto& [key, value_str] : *pairs) { |
| nya | d2c548b | 2015-12-09 03:22:32 | [diff] [blame] | 330 | if (key == "NSpid") { |
| Helmut Januschka | bfa62f7 | 2024-04-04 15:18:31 | [diff] [blame] | 331 | std::vector<std::string_view> split_value_str = SplitStringPiece( |
| nya | d2c548b | 2015-12-09 03:22:32 | [diff] [blame] | 332 | 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öm | de57333 | 2024-08-26 20:42:45 | [diff] [blame] | 339 | NOTREACHED(); |
| nya | d2c548b | 2015-12-09 03:22:32 | [diff] [blame] | 340 | } |
| 341 | return value; |
| 342 | } |
| 343 | } |
| 344 | return kNullProcessId; |
| 345 | } |
| Georg Neis | ff37fb5 | 2025-02-05 09:05:26 | [diff] [blame] | 346 | #endif // BUILDFLAG(IS_CHROMEOS) |
| nya | d2c548b | 2015-12-09 03:22:32 | [diff] [blame] | 347 | |
| Matthew Denton | f96988342 | 2023-08-08 01:44:34 | [diff] [blame] | 348 | #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) |
| 349 | bool 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 Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 359 | #if BUILDFLAG(IS_CHROMEOS) |
| 360 | // static |
| Shintaro Kawamura | f29c8fdf | 2024-03-28 03:40:08 | [diff] [blame] | 361 | void 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 Esmat | 10aa75d | 2022-06-10 11:58:46 | [diff] [blame] | 370 | bool Process::OneGroupPerRendererEnabledForTesting() { |
| 371 | return OneGroupPerRendererEnabled(); |
| Youssef Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 372 | } |
| 373 | |
| Youssef Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 374 | void Process::InitializePriority() { |
| Shintaro Kawamura | f726c129 | 2024-03-28 03:40:08 | [diff] [blame] | 375 | if (g_process_priority_delegate) { |
| 376 | g_process_priority_delegate->InitializeProcessPriority(process_); |
| 377 | return; |
| 378 | } |
| 379 | |
| Youssef Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 380 | if (!OneGroupPerRendererEnabled() || !IsValid() || !unique_token_.empty()) { |
| 381 | return; |
| 382 | } |
| Shintaro Kawamura | f726c129 | 2024-03-28 03:40:08 | [diff] [blame] | 383 | // 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 Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 386 | |
| 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 Kawamura | f726c129 | 2024-03-28 03:40:08 | [diff] [blame] | 422 | void Process::ForgetPriority() { |
| 423 | if (g_process_priority_delegate) { |
| 424 | g_process_priority_delegate->ForgetProcessPriority(process_); |
| 425 | return; |
| 426 | } |
| 427 | } |
| 428 | |
| Youssef Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 429 | // static |
| 430 | void Process::CleanUpProcessScheduled(Process process, int remaining_retries) { |
| 431 | process.CleanUpProcess(remaining_retries); |
| 432 | } |
| 433 | |
| 434 | void Process::CleanUpProcessAsync() const { |
| Youssef Esmat | 10aa75d | 2022-06-10 11:58:46 | [diff] [blame] | 435 | if (!FeatureList::IsEnabled(kOneGroupPerRenderer) || unique_token_.empty()) { |
| Youssef Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 436 | return; |
| 437 | } |
| 438 | |
| 439 | ThreadPool::PostTask(FROM_HERE, {MayBlock(), TaskPriority::BEST_EFFORT}, |
| 440 | BindOnce(&Process::CleanUpProcessScheduled, Duplicate(), |
| 441 | kCgroupDeleteRetries)); |
| 442 | } |
| 443 | |
| 444 | void Process::CleanUpProcess(int remaining_retries) const { |
| 445 | if (!OneGroupPerRendererEnabled() || unique_token_.empty()) { |
| 446 | return; |
| 447 | } |
| 448 | |
| 449 | // Try to delete the cgroup |
| Alison Gale | 81f4f2c7 | 2024-04-22 19:33:31 | [diff] [blame] | 450 | // TODO(crbug.com/40224348): We can use notify_on_release to automoatically |
| 451 | // delete the cgroup when the process has left the cgroup. |
| Youssef Esmat | c732bf8 | 2022-05-27 00:47:19 | [diff] [blame] | 452 | 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 |
| 479 | void 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] | 276aa6a | 2009-10-29 17:43:44 | [diff] [blame] | 508 | } // namespace base |