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