blob: 32bef13a1abfdf30b8077cfced87925f2ec0bfab [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>
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080028#include <cgroup_map.h>
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080029#include <processgroup/processgroup.h>
T.J. Mercier28b37f22024-06-07 18:34:19 +000030#include <processgroup/util.h>
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080031
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080032using android::base::StringPrintf;
Suren Baghdasaryan25ad3f92021-07-30 13:42:39 -070033using android::base::WriteStringToFile;
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080034
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080035static constexpr const char* CGROUP_PROCS_FILE = "/cgroup.procs";
36static constexpr const char* CGROUP_TASKS_FILE = "/tasks";
Bart Van Assche0e8e4f82023-01-06 14:03:37 -080037static constexpr const char* CGROUP_TASKS_FILE_V2 = "/cgroup.threads";
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080038
T.J. Mercierfcb86662024-08-01 20:52:30 +000039uint32_t CgroupControllerWrapper::version() const {
Yifan Hong53e0deb2019-03-22 17:01:08 -070040 CHECK(HasValue());
T.J. Mercierc76b6ad2024-10-08 23:41:31 +000041 return controller_->version();
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080042}
43
T.J. Mercierfcb86662024-08-01 20:52:30 +000044const char* CgroupControllerWrapper::name() const {
Yifan Hong53e0deb2019-03-22 17:01:08 -070045 CHECK(HasValue());
T.J. Mercierc76b6ad2024-10-08 23:41:31 +000046 return controller_->name();
Yifan Hong53e0deb2019-03-22 17:01:08 -070047}
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080048
T.J. Mercierfcb86662024-08-01 20:52:30 +000049const char* CgroupControllerWrapper::path() const {
Yifan Hong53e0deb2019-03-22 17:01:08 -070050 CHECK(HasValue());
T.J. Mercierc76b6ad2024-10-08 23:41:31 +000051 return controller_->path();
Yifan Hong53e0deb2019-03-22 17:01:08 -070052}
53
T.J. Mercierfcb86662024-08-01 20:52:30 +000054bool CgroupControllerWrapper::HasValue() const {
Yifan Hong53e0deb2019-03-22 17:01:08 -070055 return controller_ != nullptr;
56}
57
T.J. Mercierfcb86662024-08-01 20:52:30 +000058bool CgroupControllerWrapper::IsUsable() {
Suren Baghdasaryanfa7a05f2019-05-08 17:59:55 -070059 if (!HasValue()) return false;
60
Suren Baghdasaryan25eb1bf2019-06-26 11:08:50 -070061 if (state_ == UNKNOWN) {
Jiyong Parkab8a7d22020-08-11 09:32:55 +090062 if (__builtin_available(android 30, *)) {
T.J. Mercierc76b6ad2024-10-08 23:41:31 +000063 uint32_t flags = controller_->flags();
Suren Baghdasaryancee468f2020-01-23 16:18:13 -080064 state_ = (flags & CGROUPRC_CONTROLLER_FLAG_MOUNTED) != 0 ? USABLE : MISSING;
65 } else {
66 state_ = access(GetProcsFilePath("", 0, 0).c_str(), F_OK) == 0 ? USABLE : MISSING;
67 }
Suren Baghdasaryan25eb1bf2019-06-26 11:08:50 -070068 }
69
70 return state_ == USABLE;
Suren Baghdasaryanfa7a05f2019-05-08 17:59:55 -070071}
72
T.J. Mercierfcb86662024-08-01 20:52:30 +000073std::string CgroupControllerWrapper::GetTasksFilePath(const std::string& rel_path) const {
Yifan Hong53e0deb2019-03-22 17:01:08 -070074 std::string tasks_path = path();
75
76 if (!rel_path.empty()) {
77 tasks_path += "/" + rel_path;
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080078 }
Yifan Hong53e0deb2019-03-22 17:01:08 -070079 return (version() == 1) ? tasks_path + CGROUP_TASKS_FILE : tasks_path + CGROUP_TASKS_FILE_V2;
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080080}
81
T.J. Mercierfcb86662024-08-01 20:52:30 +000082std::string CgroupControllerWrapper::GetProcsFilePath(const std::string& rel_path, uid_t uid,
83 pid_t pid) const {
Yifan Hong53e0deb2019-03-22 17:01:08 -070084 std::string proc_path(path());
85 proc_path.append("/").append(rel_path);
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080086 proc_path = regex_replace(proc_path, std::regex("<uid>"), std::to_string(uid));
87 proc_path = regex_replace(proc_path, std::regex("<pid>"), std::to_string(pid));
88
89 return proc_path.append(CGROUP_PROCS_FILE);
90}
91
T.J. Mercierfcb86662024-08-01 20:52:30 +000092bool CgroupControllerWrapper::GetTaskGroup(pid_t tid, std::string* group) const {
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080093 std::string file_name = StringPrintf("/proc/%d/cgroup", tid);
94 std::string content;
95 if (!android::base::ReadFileToString(file_name, &content)) {
Wei Wangd71d3012019-03-07 11:59:12 -080096 PLOG(ERROR) << "Failed to read " << file_name;
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080097 return false;
98 }
99
100 // if group is null and tid exists return early because
101 // user is not interested in cgroup membership
102 if (group == nullptr) {
103 return true;
104 }
105
Marco Ballesiof16f9412020-06-02 15:21:13 -0700106 std::string cg_tag;
107
108 if (version() == 2) {
109 cg_tag = "0::";
110 } else {
111 cg_tag = StringPrintf(":%s:", name());
112 }
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800113 size_t start_pos = content.find(cg_tag);
114 if (start_pos == std::string::npos) {
115 return false;
116 }
117
118 start_pos += cg_tag.length() + 1; // skip '/'
119 size_t end_pos = content.find('\n', start_pos);
120 if (end_pos == std::string::npos) {
121 *group = content.substr(start_pos, std::string::npos);
122 } else {
123 *group = content.substr(start_pos, end_pos - start_pos);
124 }
125
126 return true;
127}
128
Yifan Hong53e0deb2019-03-22 17:01:08 -0700129CgroupMap::CgroupMap() {
T.J. Mercierc76b6ad2024-10-08 23:41:31 +0000130 if (!LoadDescriptors()) {
131 LOG(ERROR) << "CgroupMap::LoadDescriptors called for [" << getpid() << "] failed";
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800132 }
133}
134
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800135CgroupMap& CgroupMap::GetInstance() {
Peter Collingbournedba6d442019-03-20 21:09:46 -0700136 // Deliberately leak this object to avoid a race between destruction on
137 // process exit and concurrent access from another thread.
138 static auto* instance = new CgroupMap;
139 return *instance;
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800140}
141
T.J. Mercierc76b6ad2024-10-08 23:41:31 +0000142bool CgroupMap::LoadDescriptors() {
Yifan Hong53e0deb2019-03-22 17:01:08 -0700143 if (!loaded_) {
T.J. Mercierc76b6ad2024-10-08 23:41:31 +0000144 loaded_ = ReadDescriptors(&descriptors_);
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800145 }
Yifan Hong53e0deb2019-03-22 17:01:08 -0700146 return loaded_;
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800147}
148
Wei Wangd71d3012019-03-07 11:59:12 -0800149void CgroupMap::Print() const {
Yifan Hong53e0deb2019-03-22 17:01:08 -0700150 if (!loaded_) {
Wei Wangd71d3012019-03-07 11:59:12 -0800151 LOG(ERROR) << "CgroupMap::Print called for [" << getpid()
T.J. Merciera09ee8e2024-10-08 23:41:27 +0000152 << "] failed, cgroups were not initialized properly";
Wei Wangd71d3012019-03-07 11:59:12 -0800153 return;
154 }
T.J. Mercierc76b6ad2024-10-08 23:41:31 +0000155 LOG(INFO) << "Controller count = " << descriptors_.size();
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800156
157 LOG(INFO) << "Mounted cgroups:";
Yifan Hong53e0deb2019-03-22 17:01:08 -0700158
T.J. Mercierc76b6ad2024-10-08 23:41:31 +0000159 for (const auto& [name, descriptor] : descriptors_) {
160 LOG(INFO) << "\t" << descriptor.controller()->name() << " ver "
161 << descriptor.controller()->version() << " path "
162 << descriptor.controller()->path() << " flags "
163 << descriptor.controller()->flags();
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800164 }
165}
166
T.J. Mercierfcb86662024-08-01 20:52:30 +0000167CgroupControllerWrapper CgroupMap::FindController(const std::string& name) const {
Yifan Hong53e0deb2019-03-22 17:01:08 -0700168 if (!loaded_) {
Wei Wangd71d3012019-03-07 11:59:12 -0800169 LOG(ERROR) << "CgroupMap::FindController called for [" << getpid()
T.J. Mercierc76b6ad2024-10-08 23:41:31 +0000170 << "] failed, cgroups were not initialized properly";
T.J. Mercierfcb86662024-08-01 20:52:30 +0000171 return CgroupControllerWrapper(nullptr);
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800172 }
173
T.J. Mercierc76b6ad2024-10-08 23:41:31 +0000174 if (const auto it = descriptors_.find(name); it != descriptors_.end()) {
175 return CgroupControllerWrapper(it->second.controller());
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800176 }
177
T.J. Mercierfcb86662024-08-01 20:52:30 +0000178 return CgroupControllerWrapper(nullptr);
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800179}
Suren Baghdasaryan25ad3f92021-07-30 13:42:39 -0700180
T.J. Mercierfcb86662024-08-01 20:52:30 +0000181CgroupControllerWrapper CgroupMap::FindControllerByPath(const std::string& path) const {
Suren Baghdasaryan9e3ace52021-06-16 17:01:19 -0700182 if (!loaded_) {
183 LOG(ERROR) << "CgroupMap::FindControllerByPath called for [" << getpid()
T.J. Mercierc76b6ad2024-10-08 23:41:31 +0000184 << "] failed, cgroups were not initialized properly";
T.J. Mercierfcb86662024-08-01 20:52:30 +0000185 return CgroupControllerWrapper(nullptr);
Suren Baghdasaryan9e3ace52021-06-16 17:01:19 -0700186 }
187
T.J. Mercierc76b6ad2024-10-08 23:41:31 +0000188 for (const auto& [name, descriptor] : descriptors_) {
189 if (path.starts_with(descriptor.controller()->path())) {
190 return CgroupControllerWrapper(descriptor.controller());
Suren Baghdasaryan9e3ace52021-06-16 17:01:19 -0700191 }
192 }
193
T.J. Mercierfcb86662024-08-01 20:52:30 +0000194 return CgroupControllerWrapper(nullptr);
Suren Baghdasaryan9e3ace52021-06-16 17:01:19 -0700195}
196
T.J. Mercier787ddbc2024-10-08 23:41:34 +0000197bool CgroupMap::ActivateControllers(const std::string& path) const {
198 return ::ActivateControllers(path, descriptors_);
Suren Baghdasaryan25ad3f92021-07-30 13:42:39 -0700199}