xref: /aosp_15_r20/external/libchrome/base/process/process_linux.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1*635a8641SAndroid Build Coastguard Worker // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker 
5*635a8641SAndroid Build Coastguard Worker #include "base/process/process.h"
6*635a8641SAndroid Build Coastguard Worker 
7*635a8641SAndroid Build Coastguard Worker #include <errno.h>
8*635a8641SAndroid Build Coastguard Worker #include <sys/resource.h>
9*635a8641SAndroid Build Coastguard Worker 
10*635a8641SAndroid Build Coastguard Worker #include "base/files/file_util.h"
11*635a8641SAndroid Build Coastguard Worker #include "base/logging.h"
12*635a8641SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
13*635a8641SAndroid Build Coastguard Worker #include "base/strings/string_split.h"
14*635a8641SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
15*635a8641SAndroid Build Coastguard Worker #include "base/synchronization/lock.h"
16*635a8641SAndroid Build Coastguard Worker #include "base/threading/thread_restrictions.h"
17*635a8641SAndroid Build Coastguard Worker #include "build/build_config.h"
18*635a8641SAndroid Build Coastguard Worker 
19*635a8641SAndroid Build Coastguard Worker // Not defined on AIX by default.
20*635a8641SAndroid Build Coastguard Worker #if defined(OS_AIX)
21*635a8641SAndroid Build Coastguard Worker #define RLIMIT_NICE 20
22*635a8641SAndroid Build Coastguard Worker #endif
23*635a8641SAndroid Build Coastguard Worker 
24*635a8641SAndroid Build Coastguard Worker namespace base {
25*635a8641SAndroid Build Coastguard Worker 
26*635a8641SAndroid Build Coastguard Worker namespace {
27*635a8641SAndroid Build Coastguard Worker 
28*635a8641SAndroid Build Coastguard Worker const int kForegroundPriority = 0;
29*635a8641SAndroid Build Coastguard Worker 
30*635a8641SAndroid Build Coastguard Worker #if defined(OS_CHROMEOS)
31*635a8641SAndroid Build Coastguard Worker // We are more aggressive in our lowering of background process priority
32*635a8641SAndroid Build Coastguard Worker // for chromeos as we have much more control over other processes running
33*635a8641SAndroid Build Coastguard Worker // on the machine.
34*635a8641SAndroid Build Coastguard Worker //
35*635a8641SAndroid Build Coastguard Worker // TODO(davemoore) Refactor this by adding support for higher levels to set
36*635a8641SAndroid Build Coastguard Worker // the foregrounding / backgrounding process so we don't have to keep
37*635a8641SAndroid Build Coastguard Worker // chrome / chromeos specific logic here.
38*635a8641SAndroid Build Coastguard Worker const int kBackgroundPriority = 19;
39*635a8641SAndroid Build Coastguard Worker const char kControlPath[] = "/sys/fs/cgroup/cpu%s/cgroup.procs";
40*635a8641SAndroid Build Coastguard Worker const char kForeground[] = "/chrome_renderers/foreground";
41*635a8641SAndroid Build Coastguard Worker const char kBackground[] = "/chrome_renderers/background";
42*635a8641SAndroid Build Coastguard Worker const char kProcPath[] = "/proc/%d/cgroup";
43*635a8641SAndroid Build Coastguard Worker 
44*635a8641SAndroid Build Coastguard Worker struct CGroups {
45*635a8641SAndroid Build Coastguard Worker   // Check for cgroups files. ChromeOS supports these by default. It creates
46*635a8641SAndroid Build Coastguard Worker   // a cgroup mount in /sys/fs/cgroup and then configures two cpu task groups,
47*635a8641SAndroid Build Coastguard Worker   // one contains at most a single foreground renderer and the other contains
48*635a8641SAndroid Build Coastguard Worker   // all background renderers. This allows us to limit the impact of background
49*635a8641SAndroid Build Coastguard Worker   // renderers on foreground ones to a greater level than simple renicing.
50*635a8641SAndroid Build Coastguard Worker   bool enabled;
51*635a8641SAndroid Build Coastguard Worker   base::FilePath foreground_file;
52*635a8641SAndroid Build Coastguard Worker   base::FilePath background_file;
53*635a8641SAndroid Build Coastguard Worker 
CGroupsbase::__anon8d362da50111::CGroups54*635a8641SAndroid Build Coastguard Worker   CGroups() {
55*635a8641SAndroid Build Coastguard Worker     foreground_file =
56*635a8641SAndroid Build Coastguard Worker         base::FilePath(base::StringPrintf(kControlPath, kForeground));
57*635a8641SAndroid Build Coastguard Worker     background_file =
58*635a8641SAndroid Build Coastguard Worker         base::FilePath(base::StringPrintf(kControlPath, kBackground));
59*635a8641SAndroid Build Coastguard Worker     base::FileSystemType foreground_type;
60*635a8641SAndroid Build Coastguard Worker     base::FileSystemType background_type;
61*635a8641SAndroid Build Coastguard Worker     enabled =
62*635a8641SAndroid Build Coastguard Worker         base::GetFileSystemType(foreground_file, &foreground_type) &&
63*635a8641SAndroid Build Coastguard Worker         base::GetFileSystemType(background_file, &background_type) &&
64*635a8641SAndroid Build Coastguard Worker         foreground_type == FILE_SYSTEM_CGROUP &&
65*635a8641SAndroid Build Coastguard Worker         background_type == FILE_SYSTEM_CGROUP;
66*635a8641SAndroid Build Coastguard Worker   }
67*635a8641SAndroid Build Coastguard Worker 
Getbase::__anon8d362da50111::CGroups68*635a8641SAndroid Build Coastguard Worker   static CGroups& Get() {
69*635a8641SAndroid Build Coastguard Worker     static auto& groups = *new CGroups;
70*635a8641SAndroid Build Coastguard Worker     return groups;
71*635a8641SAndroid Build Coastguard Worker   }
72*635a8641SAndroid Build Coastguard Worker };
73*635a8641SAndroid Build Coastguard Worker #else
74*635a8641SAndroid Build Coastguard Worker const int kBackgroundPriority = 5;
75*635a8641SAndroid Build Coastguard Worker #endif  // defined(OS_CHROMEOS)
76*635a8641SAndroid Build Coastguard Worker 
CanReraisePriority()77*635a8641SAndroid Build Coastguard Worker bool CanReraisePriority() {
78*635a8641SAndroid Build Coastguard Worker   // We won't be able to raise the priority if we don't have the right rlimit.
79*635a8641SAndroid Build Coastguard Worker   // The limit may be adjusted in /etc/security/limits.conf for PAM systems.
80*635a8641SAndroid Build Coastguard Worker   struct rlimit rlim;
81*635a8641SAndroid Build Coastguard Worker   return (getrlimit(RLIMIT_NICE, &rlim) == 0) &&
82*635a8641SAndroid Build Coastguard Worker          (20 - kForegroundPriority) <= static_cast<int>(rlim.rlim_cur);
83*635a8641SAndroid Build Coastguard Worker }
84*635a8641SAndroid Build Coastguard Worker 
85*635a8641SAndroid Build Coastguard Worker }  // namespace
86*635a8641SAndroid Build Coastguard Worker 
87*635a8641SAndroid Build Coastguard Worker // static
CanBackgroundProcesses()88*635a8641SAndroid Build Coastguard Worker bool Process::CanBackgroundProcesses() {
89*635a8641SAndroid Build Coastguard Worker #if defined(OS_CHROMEOS)
90*635a8641SAndroid Build Coastguard Worker   if (CGroups::Get().enabled)
91*635a8641SAndroid Build Coastguard Worker     return true;
92*635a8641SAndroid Build Coastguard Worker #endif  // defined(OS_CHROMEOS)
93*635a8641SAndroid Build Coastguard Worker 
94*635a8641SAndroid Build Coastguard Worker   static const bool can_reraise_priority = CanReraisePriority();
95*635a8641SAndroid Build Coastguard Worker   return can_reraise_priority;
96*635a8641SAndroid Build Coastguard Worker }
97*635a8641SAndroid Build Coastguard Worker 
IsProcessBackgrounded() const98*635a8641SAndroid Build Coastguard Worker bool Process::IsProcessBackgrounded() const {
99*635a8641SAndroid Build Coastguard Worker   DCHECK(IsValid());
100*635a8641SAndroid Build Coastguard Worker 
101*635a8641SAndroid Build Coastguard Worker #if defined(OS_CHROMEOS)
102*635a8641SAndroid Build Coastguard Worker   if (CGroups::Get().enabled) {
103*635a8641SAndroid Build Coastguard Worker     // Used to allow reading the process priority from proc on thread launch.
104*635a8641SAndroid Build Coastguard Worker     base::ThreadRestrictions::ScopedAllowIO allow_io;
105*635a8641SAndroid Build Coastguard Worker     std::string proc;
106*635a8641SAndroid Build Coastguard Worker     if (base::ReadFileToString(
107*635a8641SAndroid Build Coastguard Worker             base::FilePath(StringPrintf(kProcPath, process_)), &proc)) {
108*635a8641SAndroid Build Coastguard Worker       return IsProcessBackgroundedCGroup(proc);
109*635a8641SAndroid Build Coastguard Worker     }
110*635a8641SAndroid Build Coastguard Worker     return false;
111*635a8641SAndroid Build Coastguard Worker   }
112*635a8641SAndroid Build Coastguard Worker #endif  // defined(OS_CHROMEOS)
113*635a8641SAndroid Build Coastguard Worker 
114*635a8641SAndroid Build Coastguard Worker   return GetPriority() == kBackgroundPriority;
115*635a8641SAndroid Build Coastguard Worker }
116*635a8641SAndroid Build Coastguard Worker 
SetProcessBackgrounded(bool background)117*635a8641SAndroid Build Coastguard Worker bool Process::SetProcessBackgrounded(bool background) {
118*635a8641SAndroid Build Coastguard Worker   DCHECK(IsValid());
119*635a8641SAndroid Build Coastguard Worker 
120*635a8641SAndroid Build Coastguard Worker #if defined(OS_CHROMEOS)
121*635a8641SAndroid Build Coastguard Worker   if (CGroups::Get().enabled) {
122*635a8641SAndroid Build Coastguard Worker     std::string pid = IntToString(process_);
123*635a8641SAndroid Build Coastguard Worker     const base::FilePath file = background ? CGroups::Get().background_file
124*635a8641SAndroid Build Coastguard Worker                                            : CGroups::Get().foreground_file;
125*635a8641SAndroid Build Coastguard Worker     return base::WriteFile(file, pid.c_str(), pid.size()) > 0;
126*635a8641SAndroid Build Coastguard Worker   }
127*635a8641SAndroid Build Coastguard Worker #endif  // defined(OS_CHROMEOS)
128*635a8641SAndroid Build Coastguard Worker 
129*635a8641SAndroid Build Coastguard Worker   if (!CanBackgroundProcesses())
130*635a8641SAndroid Build Coastguard Worker     return false;
131*635a8641SAndroid Build Coastguard Worker 
132*635a8641SAndroid Build Coastguard Worker   int priority = background ? kBackgroundPriority : kForegroundPriority;
133*635a8641SAndroid Build Coastguard Worker   int result = setpriority(PRIO_PROCESS, process_, priority);
134*635a8641SAndroid Build Coastguard Worker   DPCHECK(result == 0);
135*635a8641SAndroid Build Coastguard Worker   return result == 0;
136*635a8641SAndroid Build Coastguard Worker }
137*635a8641SAndroid Build Coastguard Worker 
138*635a8641SAndroid Build Coastguard Worker #if defined(OS_CHROMEOS)
IsProcessBackgroundedCGroup(const StringPiece & cgroup_contents)139*635a8641SAndroid Build Coastguard Worker bool IsProcessBackgroundedCGroup(const StringPiece& cgroup_contents) {
140*635a8641SAndroid Build Coastguard Worker   // The process can be part of multiple control groups, and for each cgroup
141*635a8641SAndroid Build Coastguard Worker   // hierarchy there's an entry in the file. We look for a control group
142*635a8641SAndroid Build Coastguard Worker   // named "/chrome_renderers/background" to determine if the process is
143*635a8641SAndroid Build Coastguard Worker   // backgrounded. crbug.com/548818.
144*635a8641SAndroid Build Coastguard Worker   std::vector<StringPiece> lines = SplitStringPiece(
145*635a8641SAndroid Build Coastguard Worker       cgroup_contents, "\n", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
146*635a8641SAndroid Build Coastguard Worker   for (const auto& line : lines) {
147*635a8641SAndroid Build Coastguard Worker     std::vector<StringPiece> fields =
148*635a8641SAndroid Build Coastguard Worker         SplitStringPiece(line, ":", TRIM_WHITESPACE, SPLIT_WANT_ALL);
149*635a8641SAndroid Build Coastguard Worker     if (fields.size() != 3U) {
150*635a8641SAndroid Build Coastguard Worker       NOTREACHED();
151*635a8641SAndroid Build Coastguard Worker       continue;
152*635a8641SAndroid Build Coastguard Worker     }
153*635a8641SAndroid Build Coastguard Worker     if (fields[2] == kBackground)
154*635a8641SAndroid Build Coastguard Worker       return true;
155*635a8641SAndroid Build Coastguard Worker   }
156*635a8641SAndroid Build Coastguard Worker 
157*635a8641SAndroid Build Coastguard Worker   return false;
158*635a8641SAndroid Build Coastguard Worker }
159*635a8641SAndroid Build Coastguard Worker #endif  // defined(OS_CHROMEOS)
160*635a8641SAndroid Build Coastguard Worker 
161*635a8641SAndroid Build Coastguard Worker #if defined(OS_CHROMEOS)
162*635a8641SAndroid Build Coastguard Worker // Reads /proc/<pid>/status and returns the PID in its PID namespace.
163*635a8641SAndroid Build Coastguard Worker // If the process is not in a PID namespace or /proc/<pid>/status does not
164*635a8641SAndroid Build Coastguard Worker // report NSpid, kNullProcessId is returned.
GetPidInNamespace() const165*635a8641SAndroid Build Coastguard Worker ProcessId Process::GetPidInNamespace() const {
166*635a8641SAndroid Build Coastguard Worker   std::string status;
167*635a8641SAndroid Build Coastguard Worker   {
168*635a8641SAndroid Build Coastguard Worker     // Synchronously reading files in /proc does not hit the disk.
169*635a8641SAndroid Build Coastguard Worker     ThreadRestrictions::ScopedAllowIO allow_io;
170*635a8641SAndroid Build Coastguard Worker     FilePath status_file =
171*635a8641SAndroid Build Coastguard Worker         FilePath("/proc").Append(IntToString(process_)).Append("status");
172*635a8641SAndroid Build Coastguard Worker     if (!ReadFileToString(status_file, &status)) {
173*635a8641SAndroid Build Coastguard Worker       return kNullProcessId;
174*635a8641SAndroid Build Coastguard Worker     }
175*635a8641SAndroid Build Coastguard Worker   }
176*635a8641SAndroid Build Coastguard Worker 
177*635a8641SAndroid Build Coastguard Worker   StringPairs pairs;
178*635a8641SAndroid Build Coastguard Worker   SplitStringIntoKeyValuePairs(status, ':', '\n', &pairs);
179*635a8641SAndroid Build Coastguard Worker   for (const auto& pair : pairs) {
180*635a8641SAndroid Build Coastguard Worker     const std::string& key = pair.first;
181*635a8641SAndroid Build Coastguard Worker     const std::string& value_str = pair.second;
182*635a8641SAndroid Build Coastguard Worker     if (key == "NSpid") {
183*635a8641SAndroid Build Coastguard Worker       std::vector<StringPiece> split_value_str = SplitStringPiece(
184*635a8641SAndroid Build Coastguard Worker           value_str, "\t", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
185*635a8641SAndroid Build Coastguard Worker       if (split_value_str.size() <= 1) {
186*635a8641SAndroid Build Coastguard Worker         return kNullProcessId;
187*635a8641SAndroid Build Coastguard Worker       }
188*635a8641SAndroid Build Coastguard Worker       int value;
189*635a8641SAndroid Build Coastguard Worker       // The last value in the list is the PID in the namespace.
190*635a8641SAndroid Build Coastguard Worker       if (!StringToInt(split_value_str.back(), &value)) {
191*635a8641SAndroid Build Coastguard Worker         NOTREACHED();
192*635a8641SAndroid Build Coastguard Worker         return kNullProcessId;
193*635a8641SAndroid Build Coastguard Worker       }
194*635a8641SAndroid Build Coastguard Worker       return value;
195*635a8641SAndroid Build Coastguard Worker     }
196*635a8641SAndroid Build Coastguard Worker   }
197*635a8641SAndroid Build Coastguard Worker   return kNullProcessId;
198*635a8641SAndroid Build Coastguard Worker }
199*635a8641SAndroid Build Coastguard Worker #endif  // defined(OS_CHROMEOS)
200*635a8641SAndroid Build Coastguard Worker 
201*635a8641SAndroid Build Coastguard Worker }  // namespace base
202