blob: aeccfe89b91ba5aa1572d406724b59137bde6485 [file] [log] [blame]
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -08001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "libprocessgroup"
19
20#include <errno.h>
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080021#include <unistd.h>
22
23#include <regex>
24
25#include <android-base/file.h>
26#include <android-base/logging.h>
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080027#include <android-base/stringprintf.h>
Priyanka Advani (xWF)691ad732024-10-08 18:54:37 +000028#include <android-base/strings.h>
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080029#include <cgroup_map.h>
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080030#include <processgroup/processgroup.h>
T.J. Mercier28b37f22024-06-07 18:34:19 +000031#include <processgroup/util.h>
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080032
Priyanka Advani (xWF)691ad732024-10-08 18:54:37 +000033using android::base::StartsWith;
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080034using android::base::StringPrintf;
Suren Baghdasaryan25ad3f92021-07-30 13:42:39 -070035using android::base::WriteStringToFile;
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080036
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080037static constexpr const char* CGROUP_PROCS_FILE = "/cgroup.procs";
38static constexpr const char* CGROUP_TASKS_FILE = "/tasks";
Bart Van Assche0e8e4f82023-01-06 14:03:37 -080039static constexpr const char* CGROUP_TASKS_FILE_V2 = "/cgroup.threads";
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080040
T.J. Mercierfcb86662024-08-01 20:52:30 +000041uint32_t CgroupControllerWrapper::version() const {
Yifan Hong53e0deb2019-03-22 17:01:08 -070042 CHECK(HasValue());
Priyanka Advani (xWF)691ad732024-10-08 18:54:37 +000043 return ACgroupController_getVersion(controller_);
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080044}
45
T.J. Mercierfcb86662024-08-01 20:52:30 +000046const char* CgroupControllerWrapper::name() const {
Yifan Hong53e0deb2019-03-22 17:01:08 -070047 CHECK(HasValue());
Priyanka Advani (xWF)691ad732024-10-08 18:54:37 +000048 return ACgroupController_getName(controller_);
Yifan Hong53e0deb2019-03-22 17:01:08 -070049}
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080050
T.J. Mercierfcb86662024-08-01 20:52:30 +000051const char* CgroupControllerWrapper::path() const {
Yifan Hong53e0deb2019-03-22 17:01:08 -070052 CHECK(HasValue());
Priyanka Advani (xWF)691ad732024-10-08 18:54:37 +000053 return ACgroupController_getPath(controller_);
Yifan Hong53e0deb2019-03-22 17:01:08 -070054}
55
T.J. Mercierfcb86662024-08-01 20:52:30 +000056bool CgroupControllerWrapper::HasValue() const {
Yifan Hong53e0deb2019-03-22 17:01:08 -070057 return controller_ != nullptr;
58}
59
T.J. Mercierfcb86662024-08-01 20:52:30 +000060bool CgroupControllerWrapper::IsUsable() {
Suren Baghdasaryanfa7a05f2019-05-08 17:59:55 -070061 if (!HasValue()) return false;
62
Suren Baghdasaryan25eb1bf2019-06-26 11:08:50 -070063 if (state_ == UNKNOWN) {
Jiyong Parkab8a7d22020-08-11 09:32:55 +090064 if (__builtin_available(android 30, *)) {
Priyanka Advani (xWF)691ad732024-10-08 18:54:37 +000065 uint32_t flags = ACgroupController_getFlags(controller_);
Suren Baghdasaryancee468f2020-01-23 16:18:13 -080066 state_ = (flags & CGROUPRC_CONTROLLER_FLAG_MOUNTED) != 0 ? USABLE : MISSING;
67 } else {
68 state_ = access(GetProcsFilePath("", 0, 0).c_str(), F_OK) == 0 ? USABLE : MISSING;
69 }
Suren Baghdasaryan25eb1bf2019-06-26 11:08:50 -070070 }
71
72 return state_ == USABLE;
Suren Baghdasaryanfa7a05f2019-05-08 17:59:55 -070073}
74
T.J. Mercierfcb86662024-08-01 20:52:30 +000075std::string CgroupControllerWrapper::GetTasksFilePath(const std::string& rel_path) const {
Yifan Hong53e0deb2019-03-22 17:01:08 -070076 std::string tasks_path = path();
77
78 if (!rel_path.empty()) {
79 tasks_path += "/" + rel_path;
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080080 }
Yifan Hong53e0deb2019-03-22 17:01:08 -070081 return (version() == 1) ? tasks_path + CGROUP_TASKS_FILE : tasks_path + CGROUP_TASKS_FILE_V2;
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080082}
83
T.J. Mercierfcb86662024-08-01 20:52:30 +000084std::string CgroupControllerWrapper::GetProcsFilePath(const std::string& rel_path, uid_t uid,
85 pid_t pid) const {
Yifan Hong53e0deb2019-03-22 17:01:08 -070086 std::string proc_path(path());
87 proc_path.append("/").append(rel_path);
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080088 proc_path = regex_replace(proc_path, std::regex("<uid>"), std::to_string(uid));
89 proc_path = regex_replace(proc_path, std::regex("<pid>"), std::to_string(pid));
90
91 return proc_path.append(CGROUP_PROCS_FILE);
92}
93
T.J. Mercierfcb86662024-08-01 20:52:30 +000094bool CgroupControllerWrapper::GetTaskGroup(pid_t tid, std::string* group) const {
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080095 std::string file_name = StringPrintf("/proc/%d/cgroup", tid);
96 std::string content;
97 if (!android::base::ReadFileToString(file_name, &content)) {
Wei Wangd71d3012019-03-07 11:59:12 -080098 PLOG(ERROR) << "Failed to read " << file_name;
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080099 return false;
100 }
101
102 // if group is null and tid exists return early because
103 // user is not interested in cgroup membership
104 if (group == nullptr) {
105 return true;
106 }
107
Marco Ballesiof16f9412020-06-02 15:21:13 -0700108 std::string cg_tag;
109
110 if (version() == 2) {
111 cg_tag = "0::";
112 } else {
113 cg_tag = StringPrintf(":%s:", name());
114 }
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800115 size_t start_pos = content.find(cg_tag);
116 if (start_pos == std::string::npos) {
117 return false;
118 }
119
120 start_pos += cg_tag.length() + 1; // skip '/'
121 size_t end_pos = content.find('\n', start_pos);
122 if (end_pos == std::string::npos) {
123 *group = content.substr(start_pos, std::string::npos);
124 } else {
125 *group = content.substr(start_pos, end_pos - start_pos);
126 }
127
128 return true;
129}
130
Yifan Hong53e0deb2019-03-22 17:01:08 -0700131CgroupMap::CgroupMap() {
Priyanka Advani (xWF)691ad732024-10-08 18:54:37 +0000132 if (!LoadRcFile()) {
133 LOG(ERROR) << "CgroupMap::LoadRcFile called for [" << getpid() << "] failed";
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800134 }
135}
136
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800137CgroupMap& CgroupMap::GetInstance() {
Peter Collingbournedba6d442019-03-20 21:09:46 -0700138 // Deliberately leak this object to avoid a race between destruction on
139 // process exit and concurrent access from another thread.
140 static auto* instance = new CgroupMap;
141 return *instance;
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800142}
143
Priyanka Advani (xWF)691ad732024-10-08 18:54:37 +0000144bool CgroupMap::LoadRcFile() {
Yifan Hong53e0deb2019-03-22 17:01:08 -0700145 if (!loaded_) {
Priyanka Advani (xWF)691ad732024-10-08 18:54:37 +0000146 loaded_ = (ACgroupFile_getVersion() != 0);
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800147 }
Yifan Hong53e0deb2019-03-22 17:01:08 -0700148 return loaded_;
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800149}
150
Wei Wangd71d3012019-03-07 11:59:12 -0800151void CgroupMap::Print() const {
Yifan Hong53e0deb2019-03-22 17:01:08 -0700152 if (!loaded_) {
Wei Wangd71d3012019-03-07 11:59:12 -0800153 LOG(ERROR) << "CgroupMap::Print called for [" << getpid()
T.J. Merciera09ee8e2024-10-08 23:41:27 +0000154 << "] failed, cgroups were not initialized properly";
Wei Wangd71d3012019-03-07 11:59:12 -0800155 return;
156 }
Priyanka Advani (xWF)691ad732024-10-08 18:54:37 +0000157 LOG(INFO) << "File version = " << ACgroupFile_getVersion();
158 LOG(INFO) << "File controller count = " << ACgroupFile_getControllerCount();
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800159
160 LOG(INFO) << "Mounted cgroups:";
Yifan Hong53e0deb2019-03-22 17:01:08 -0700161
Priyanka Advani (xWF)691ad732024-10-08 18:54:37 +0000162 auto controller_count = ACgroupFile_getControllerCount();
163 for (uint32_t i = 0; i < controller_count; ++i) {
164 const ACgroupController* controller = ACgroupFile_getController(i);
165 if (__builtin_available(android 30, *)) {
166 LOG(INFO) << "\t" << ACgroupController_getName(controller) << " ver "
167 << ACgroupController_getVersion(controller) << " path "
168 << ACgroupController_getPath(controller) << " flags "
169 << ACgroupController_getFlags(controller);
170 } else {
171 LOG(INFO) << "\t" << ACgroupController_getName(controller) << " ver "
172 << ACgroupController_getVersion(controller) << " path "
173 << ACgroupController_getPath(controller);
174 }
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800175 }
176}
177
T.J. Mercierfcb86662024-08-01 20:52:30 +0000178CgroupControllerWrapper CgroupMap::FindController(const std::string& name) const {
Yifan Hong53e0deb2019-03-22 17:01:08 -0700179 if (!loaded_) {
Wei Wangd71d3012019-03-07 11:59:12 -0800180 LOG(ERROR) << "CgroupMap::FindController called for [" << getpid()
Priyanka Advani (xWF)691ad732024-10-08 18:54:37 +0000181 << "] failed, RC file was not initialized properly";
T.J. Mercierfcb86662024-08-01 20:52:30 +0000182 return CgroupControllerWrapper(nullptr);
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800183 }
184
Priyanka Advani (xWF)691ad732024-10-08 18:54:37 +0000185 auto controller_count = ACgroupFile_getControllerCount();
186 for (uint32_t i = 0; i < controller_count; ++i) {
187 const ACgroupController* controller = ACgroupFile_getController(i);
188 if (name == ACgroupController_getName(controller)) {
189 return CgroupControllerWrapper(controller);
190 }
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800191 }
192
T.J. Mercierfcb86662024-08-01 20:52:30 +0000193 return CgroupControllerWrapper(nullptr);
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800194}
Suren Baghdasaryan25ad3f92021-07-30 13:42:39 -0700195
T.J. Mercierfcb86662024-08-01 20:52:30 +0000196CgroupControllerWrapper CgroupMap::FindControllerByPath(const std::string& path) const {
Suren Baghdasaryan9e3ace52021-06-16 17:01:19 -0700197 if (!loaded_) {
198 LOG(ERROR) << "CgroupMap::FindControllerByPath called for [" << getpid()
Priyanka Advani (xWF)691ad732024-10-08 18:54:37 +0000199 << "] failed, RC file was not initialized properly";
T.J. Mercierfcb86662024-08-01 20:52:30 +0000200 return CgroupControllerWrapper(nullptr);
Suren Baghdasaryan9e3ace52021-06-16 17:01:19 -0700201 }
202
Priyanka Advani (xWF)691ad732024-10-08 18:54:37 +0000203 auto controller_count = ACgroupFile_getControllerCount();
204 for (uint32_t i = 0; i < controller_count; ++i) {
205 const ACgroupController* controller = ACgroupFile_getController(i);
206 if (StartsWith(path, ACgroupController_getPath(controller))) {
207 return CgroupControllerWrapper(controller);
Suren Baghdasaryan9e3ace52021-06-16 17:01:19 -0700208 }
209 }
210
T.J. Mercierfcb86662024-08-01 20:52:30 +0000211 return CgroupControllerWrapper(nullptr);
Suren Baghdasaryan9e3ace52021-06-16 17:01:19 -0700212}
213
Priyanka Advani (xWF)0fa49252024-10-08 18:54:37 +0000214int CgroupMap::ActivateControllers(const std::string& path) const {
Priyanka Advani (xWF)691ad732024-10-08 18:54:37 +0000215 if (__builtin_available(android 30, *)) {
216 auto controller_count = ACgroupFile_getControllerCount();
217 for (uint32_t i = 0; i < controller_count; ++i) {
218 const ACgroupController* controller = ACgroupFile_getController(i);
219 const uint32_t flags = ACgroupController_getFlags(controller);
220 uint32_t max_activation_depth = UINT32_MAX;
221 if (__builtin_available(android 36, *)) {
222 max_activation_depth = ACgroupController_getMaxActivationDepth(controller);
223 }
T.J. Merciera09ee8e2024-10-08 23:41:27 +0000224 const int depth = GetCgroupDepth(ACgroupController_getPath(controller), path);
Priyanka Advani (xWF)0fa49252024-10-08 18:54:37 +0000225
Priyanka Advani (xWF)691ad732024-10-08 18:54:37 +0000226 if (flags & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION && depth < max_activation_depth) {
227 std::string str("+");
228 str.append(ACgroupController_getName(controller));
229 if (!WriteStringToFile(str, path + "/cgroup.subtree_control")) {
230 if (flags & CGROUPRC_CONTROLLER_FLAG_OPTIONAL) {
231 PLOG(WARNING) << "Activation of cgroup controller " << str
232 << " failed in path " << path;
233 } else {
234 return -errno;
235 }
Priyanka Advani (xWF)0fa49252024-10-08 18:54:37 +0000236 }
237 }
238 }
Priyanka Advani (xWF)691ad732024-10-08 18:54:37 +0000239 return 0;
Priyanka Advani (xWF)0fa49252024-10-08 18:54:37 +0000240 }
Priyanka Advani (xWF)691ad732024-10-08 18:54:37 +0000241 return -ENOSYS;
Suren Baghdasaryan25ad3f92021-07-30 13:42:39 -0700242}