1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/chromeos/power/freezer_cgroup_process_manager.h"
10 #include "base/bind_helpers.h"
11 #include "base/files/file_util.h"
12 #include "base/logging.h"
13 #include "base/sequenced_task_runner.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "content/public/browser/browser_thread.h"
20 const char kFreezerPath
[] = "/sys/fs/cgroup/freezer/chrome_renderers";
21 const char kToBeFrozen
[] = "to_be_frozen";
22 const char kFreezerState
[] = "freezer.state";
23 const char kCgroupProcs
[] = "cgroup.procs";
25 const char kFreezeCommand
[] = "FROZEN";
26 const char kThawCommand
[] = "THAWED";
30 class FreezerCgroupProcessManager::FileWorker
{
32 // Called on UI thread.
33 explicit FileWorker(scoped_refptr
<base::SequencedTaskRunner
> file_thread
)
34 : ui_thread_(content::BrowserThread::GetMessageLoopProxyForThread(
35 content::BrowserThread::UI
)),
36 file_thread_(file_thread
) {
37 DCHECK(ui_thread_
->RunsTasksOnCurrentThread());
40 // Called on FILE thread.
41 virtual ~FileWorker() { DCHECK(file_thread_
->RunsTasksOnCurrentThread()); }
44 DCHECK(file_thread_
->RunsTasksOnCurrentThread());
46 default_control_path_
= base::FilePath(kFreezerPath
).Append(kCgroupProcs
);
47 to_be_frozen_control_path_
= base::FilePath(kFreezerPath
)
48 .AppendASCII(kToBeFrozen
)
49 .AppendASCII(kCgroupProcs
);
50 to_be_frozen_state_path_
= base::FilePath(kFreezerPath
)
51 .AppendASCII(kToBeFrozen
)
52 .AppendASCII(kFreezerState
);
53 enabled_
= base::PathIsWritable(default_control_path_
) &&
54 base::PathIsWritable(to_be_frozen_control_path_
) &&
55 base::PathIsWritable(to_be_frozen_state_path_
);
58 LOG(WARNING
) << "Cgroup freezer does not exist or is not writable. "
59 << "Unable to freeze renderer processes.";
63 void SetShouldFreezeRenderer(base::ProcessHandle handle
, bool frozen
) {
64 DCHECK(file_thread_
->RunsTasksOnCurrentThread());
66 WriteCommandToFile(base::IntToString(handle
),
67 frozen
? to_be_frozen_control_path_
68 : default_control_path_
);
71 void FreezeRenderers() {
72 DCHECK(file_thread_
->RunsTasksOnCurrentThread());
75 LOG(ERROR
) << "Attempting to freeze renderers when the freezer cgroup is "
80 WriteCommandToFile(kFreezeCommand
, to_be_frozen_state_path_
);
83 void ThawRenderers(ResultCallback callback
) {
84 DCHECK(file_thread_
->RunsTasksOnCurrentThread());
87 LOG(ERROR
) << "Attempting to thaw renderers when the freezer cgroup is "
92 bool result
= WriteCommandToFile(kThawCommand
, to_be_frozen_state_path_
);
93 ui_thread_
->PostTask(FROM_HERE
, base::Bind(callback
, result
));
96 void CheckCanFreezeRenderers(ResultCallback callback
) {
97 DCHECK(file_thread_
->RunsTasksOnCurrentThread());
99 ui_thread_
->PostTask(FROM_HERE
, base::Bind(callback
, enabled_
));
103 bool WriteCommandToFile(const std::string
& command
,
104 const base::FilePath
& file
) {
105 int bytes
= base::WriteFile(file
, command
.c_str(), command
.size());
107 PLOG(ERROR
) << "Writing " << command
<< " to " << file
.value()
110 } else if (bytes
!= static_cast<int>(command
.size())) {
111 LOG(ERROR
) << "Only wrote " << bytes
<< " byte(s) when writing "
112 << command
<< " to " << file
.value();
118 scoped_refptr
<base::SequencedTaskRunner
> ui_thread_
;
119 scoped_refptr
<base::SequencedTaskRunner
> file_thread_
;
121 // Control path for the cgroup that is not frozen.
122 base::FilePath default_control_path_
;
124 // Control and state paths for the cgroup whose processes will be frozen.
125 base::FilePath to_be_frozen_control_path_
;
126 base::FilePath to_be_frozen_state_path_
;
130 DISALLOW_COPY_AND_ASSIGN(FileWorker
);
133 FreezerCgroupProcessManager::FreezerCgroupProcessManager()
134 : file_thread_(content::BrowserThread::GetMessageLoopProxyForThread(
135 content::BrowserThread::FILE)),
136 file_worker_(new FileWorker(file_thread_
)) {
137 file_thread_
->PostTask(FROM_HERE
,
138 base::Bind(&FileWorker::Start
,
139 base::Unretained(file_worker_
.get())));
142 FreezerCgroupProcessManager::~FreezerCgroupProcessManager() {
143 file_thread_
->DeleteSoon(FROM_HERE
, file_worker_
.release());
146 void FreezerCgroupProcessManager::SetShouldFreezeRenderer(
147 base::ProcessHandle handle
,
149 file_thread_
->PostTask(FROM_HERE
,
150 base::Bind(&FileWorker::SetShouldFreezeRenderer
,
151 base::Unretained(file_worker_
.get()),
155 void FreezerCgroupProcessManager::FreezeRenderers() {
156 file_thread_
->PostTask(FROM_HERE
,
157 base::Bind(&FileWorker::FreezeRenderers
,
158 base::Unretained(file_worker_
.get())));
161 void FreezerCgroupProcessManager::ThawRenderers(ResultCallback callback
) {
162 file_thread_
->PostTask(FROM_HERE
,
163 base::Bind(&FileWorker::ThawRenderers
,
164 base::Unretained(file_worker_
.get()),
168 void FreezerCgroupProcessManager::CheckCanFreezeRenderers(
169 ResultCallback callback
) {
170 file_thread_
->PostTask(FROM_HERE
,
171 base::Bind(&FileWorker::CheckCanFreezeRenderers
,
172 base::Unretained(file_worker_
.get()),
176 } // namespace chromeos