blob: 7fe984baeb2569bc5f8ab2b5aee241296efe0f80 [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 <fcntl.h>
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080021#include <task_profiles.h>
22#include <string>
23
24#include <android-base/file.h>
25#include <android-base/logging.h>
Suren Baghdasaryan35221b52020-11-20 17:08:51 -080026#include <android-base/properties.h>
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080027#include <android-base/stringprintf.h>
Rick Yiubc1ad962020-10-26 20:32:52 +080028#include <android-base/strings.h>
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080029#include <android-base/threads.h>
30
31#include <cutils/android_filesystem_config.h>
32
33#include <json/reader.h>
34#include <json/value.h>
35
Suren Baghdasaryaneca87cb2019-02-02 14:19:41 -080036// To avoid issues in sdk_mac build
37#if defined(__ANDROID__)
38#include <sys/prctl.h>
39#endif
40
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080041using android::base::GetThreadId;
Suren Baghdasaryan35221b52020-11-20 17:08:51 -080042using android::base::GetUintProperty;
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080043using android::base::StringPrintf;
Rick Yiubc1ad962020-10-26 20:32:52 +080044using android::base::StringReplace;
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080045using android::base::unique_fd;
46using android::base::WriteStringToFile;
47
Suren Baghdasaryan35221b52020-11-20 17:08:51 -080048static constexpr const char* TASK_PROFILE_DB_FILE = "/etc/task_profiles.json";
49static constexpr const char* TASK_PROFILE_DB_VENDOR_FILE = "/vendor/etc/task_profiles.json";
50
51static constexpr const char* TEMPLATE_TASK_PROFILE_API_FILE =
52 "/etc/task_profiles/task_profiles_%u.json";
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -080053
Suren Baghdasaryanc2ee2e52022-01-20 10:58:43 -080054class FdCacheHelper {
55 public:
56 enum FdState {
57 FDS_INACCESSIBLE = -1,
58 FDS_APP_DEPENDENT = -2,
59 FDS_NOT_CACHED = -3,
60 };
61
62 static void Cache(const std::string& path, android::base::unique_fd& fd);
63 static void Drop(android::base::unique_fd& fd);
64 static void Init(const std::string& path, android::base::unique_fd& fd);
65 static bool IsCached(const android::base::unique_fd& fd) { return fd > FDS_INACCESSIBLE; }
66
67 private:
68 static bool IsAppDependentPath(const std::string& path);
69};
70
71void FdCacheHelper::Init(const std::string& path, android::base::unique_fd& fd) {
72 // file descriptors for app-dependent paths can't be cached
73 if (IsAppDependentPath(path)) {
74 // file descriptor is not cached
75 fd.reset(FDS_APP_DEPENDENT);
76 return;
77 }
78 // file descriptor can be cached later on request
79 fd.reset(FDS_NOT_CACHED);
80}
81
82void FdCacheHelper::Cache(const std::string& path, android::base::unique_fd& fd) {
83 if (fd != FDS_NOT_CACHED) {
84 return;
85 }
86
87 if (access(path.c_str(), W_OK) != 0) {
88 // file is not accessible
89 fd.reset(FDS_INACCESSIBLE);
90 return;
91 }
92
93 unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_WRONLY | O_CLOEXEC)));
94 if (tmp_fd < 0) {
95 PLOG(ERROR) << "Failed to cache fd '" << path << "'";
96 fd.reset(FDS_INACCESSIBLE);
97 return;
98 }
99
100 fd = std::move(tmp_fd);
101}
102
103void FdCacheHelper::Drop(android::base::unique_fd& fd) {
104 if (fd == FDS_NOT_CACHED) {
105 return;
106 }
107
108 fd.reset(FDS_NOT_CACHED);
109}
110
111bool FdCacheHelper::IsAppDependentPath(const std::string& path) {
112 return path.find("<uid>", 0) != std::string::npos || path.find("<pid>", 0) != std::string::npos;
113}
114
Suren Baghdasaryan81b9f0b2020-07-01 12:34:17 -0700115void ProfileAttribute::Reset(const CgroupController& controller, const std::string& file_name) {
116 controller_ = controller;
117 file_name_ = file_name;
118}
119
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800120bool ProfileAttribute::GetPathForTask(int tid, std::string* path) const {
121 std::string subgroup;
Yifan Hong53e0deb2019-03-22 17:01:08 -0700122 if (!controller()->GetTaskGroup(tid, &subgroup)) {
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800123 return false;
124 }
125
126 if (path == nullptr) {
127 return true;
128 }
129
130 if (subgroup.empty()) {
Yifan Hong53e0deb2019-03-22 17:01:08 -0700131 *path = StringPrintf("%s/%s", controller()->path(), file_name_.c_str());
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800132 } else {
Yifan Hong53e0deb2019-03-22 17:01:08 -0700133 *path = StringPrintf("%s/%s/%s", controller()->path(), subgroup.c_str(),
134 file_name_.c_str());
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800135 }
136 return true;
137}
138
139bool SetClampsAction::ExecuteForProcess(uid_t, pid_t) const {
140 // TODO: add support when kernel supports util_clamp
141 LOG(WARNING) << "SetClampsAction::ExecuteForProcess is not supported";
142 return false;
143}
144
145bool SetClampsAction::ExecuteForTask(int) const {
146 // TODO: add support when kernel supports util_clamp
147 LOG(WARNING) << "SetClampsAction::ExecuteForTask is not supported";
148 return false;
149}
150
Suren Baghdasaryaneca87cb2019-02-02 14:19:41 -0800151// To avoid issues in sdk_mac build
152#if defined(__ANDROID__)
153
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800154bool SetTimerSlackAction::IsTimerSlackSupported(int tid) {
155 auto file = StringPrintf("/proc/%d/timerslack_ns", tid);
156
157 return (access(file.c_str(), W_OK) == 0);
158}
159
160bool SetTimerSlackAction::ExecuteForTask(int tid) const {
161 static bool sys_supports_timerslack = IsTimerSlackSupported(tid);
162
163 // v4.6+ kernels support the /proc/<tid>/timerslack_ns interface.
164 // TODO: once we've backported this, log if the open(2) fails.
165 if (sys_supports_timerslack) {
166 auto file = StringPrintf("/proc/%d/timerslack_ns", tid);
167 if (!WriteStringToFile(std::to_string(slack_), file)) {
Suren Baghdasaryan2bc52282019-02-12 17:30:26 -0800168 if (errno == ENOENT) {
169 // This happens when process is already dead
170 return true;
171 }
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800172 PLOG(ERROR) << "set_timerslack_ns write failed";
173 }
174 }
175
176 // TODO: Remove when /proc/<tid>/timerslack_ns interface is backported.
177 if (tid == 0 || tid == GetThreadId()) {
178 if (prctl(PR_SET_TIMERSLACK, slack_) == -1) {
179 PLOG(ERROR) << "set_timerslack_ns prctl failed";
180 }
181 }
182
183 return true;
184}
185
Bart Van Assche20d59bd2022-01-24 19:45:59 +0000186#else
187
188bool SetTimerSlackAction::ExecuteForTask(int) const {
189 return true;
190};
191
Suren Baghdasaryaneca87cb2019-02-02 14:19:41 -0800192#endif
193
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800194bool SetAttributeAction::ExecuteForProcess(uid_t, pid_t pid) const {
195 return ExecuteForTask(pid);
196}
197
198bool SetAttributeAction::ExecuteForTask(int tid) const {
199 std::string path;
200
201 if (!attribute_->GetPathForTask(tid, &path)) {
Wei Wangd71d3012019-03-07 11:59:12 -0800202 LOG(ERROR) << "Failed to find cgroup for tid " << tid;
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800203 return false;
204 }
205
206 if (!WriteStringToFile(value_, path)) {
207 PLOG(ERROR) << "Failed to write '" << value_ << "' to " << path;
208 return false;
209 }
210
211 return true;
212}
213
Rick Yiud4c53512021-11-21 15:57:36 +0800214SetCgroupAction::SetCgroupAction(const CgroupController& c, const std::string& p)
215 : controller_(c), path_(p) {
Suren Baghdasaryanf3bdac72022-01-20 15:41:28 -0800216 FdCacheHelper::Init(controller_.GetTasksFilePath(path_), fd_[ProfileAction::RCT_TASK]);
217 // uid and pid don't matter because IsAppDependentPath ensures the path doesn't use them
218 FdCacheHelper::Init(controller_.GetProcsFilePath(path_, 0, 0), fd_[ProfileAction::RCT_PROCESS]);
Rick Yiud4c53512021-11-21 15:57:36 +0800219}
220
Suren Baghdasaryanec885562021-09-02 19:47:12 -0700221bool SetCgroupAction::AddTidToCgroup(int tid, int fd, const char* controller_name) {
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800222 if (tid <= 0) {
223 return true;
224 }
225
226 std::string value = std::to_string(tid);
227
Suren Baghdasaryanec885562021-09-02 19:47:12 -0700228 if (TEMP_FAILURE_RETRY(write(fd, value.c_str(), value.length())) == value.length()) {
229 return true;
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800230 }
231
Suren Baghdasaryanec885562021-09-02 19:47:12 -0700232 // If the thread is in the process of exiting, don't flag an error
233 if (errno == ESRCH) {
234 return true;
235 }
236
237 // ENOSPC is returned when cpuset cgroup that we are joining has no online cpus
238 if (errno == ENOSPC && !strcmp(controller_name, "cpuset")) {
239 // This is an abnormal case happening only in testing, so report it only once
240 static bool empty_cpuset_reported = false;
241
242 if (empty_cpuset_reported) {
243 return true;
244 }
245
246 LOG(ERROR) << "Failed to add task '" << value
247 << "' into cpuset because all cpus in that cpuset are offline";
248 empty_cpuset_reported = true;
249 } else {
250 PLOG(ERROR) << "AddTidToCgroup failed to write '" << value << "'; fd=" << fd;
251 }
252
253 return false;
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800254}
255
Suren Baghdasaryanf3bdac72022-01-20 15:41:28 -0800256ProfileAction::CacheUseResult SetCgroupAction::UseCachedFd(ResourceCacheType cache_type,
257 int id) const {
258 std::lock_guard<std::mutex> lock(fd_mutex_);
259 if (FdCacheHelper::IsCached(fd_[cache_type])) {
260 // fd is cached, reuse it
261 if (!AddTidToCgroup(id, fd_[cache_type], controller()->name())) {
262 LOG(ERROR) << "Failed to add task into cgroup";
263 return ProfileAction::FAIL;
264 }
265 return ProfileAction::SUCCESS;
266 }
267
268 if (fd_[cache_type] == FdCacheHelper::FDS_INACCESSIBLE) {
269 // no permissions to access the file, ignore
270 return ProfileAction::SUCCESS;
271 }
272
273 if (cache_type == ResourceCacheType::RCT_TASK &&
274 fd_[cache_type] == FdCacheHelper::FDS_APP_DEPENDENT) {
275 // application-dependent path can't be used with tid
276 PLOG(ERROR) << "Application profile can't be applied to a thread";
277 return ProfileAction::FAIL;
278 }
279
280 return ProfileAction::UNUSED;
281}
282
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800283bool SetCgroupAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
Suren Baghdasaryanf3bdac72022-01-20 15:41:28 -0800284 CacheUseResult result = UseCachedFd(ProfileAction::RCT_PROCESS, pid);
285 if (result != ProfileAction::UNUSED) {
286 return result == ProfileAction::SUCCESS;
287 }
288
289 // fd was not cached or cached fd can't be used
Yifan Hong53e0deb2019-03-22 17:01:08 -0700290 std::string procs_path = controller()->GetProcsFilePath(path_, uid, pid);
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800291 unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(procs_path.c_str(), O_WRONLY | O_CLOEXEC)));
292 if (tmp_fd < 0) {
Elliott Hughes08b4d322019-03-14 20:06:36 -0700293 PLOG(WARNING) << "Failed to open " << procs_path;
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800294 return false;
295 }
Suren Baghdasaryanec885562021-09-02 19:47:12 -0700296 if (!AddTidToCgroup(pid, tmp_fd, controller()->name())) {
Wei Wangd71d3012019-03-07 11:59:12 -0800297 LOG(ERROR) << "Failed to add task into cgroup";
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800298 return false;
299 }
300
301 return true;
302}
303
304bool SetCgroupAction::ExecuteForTask(int tid) const {
Suren Baghdasaryanf3bdac72022-01-20 15:41:28 -0800305 CacheUseResult result = UseCachedFd(ProfileAction::RCT_TASK, tid);
306 if (result != ProfileAction::UNUSED) {
307 return result == ProfileAction::SUCCESS;
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800308 }
309
Suren Baghdasaryanf3bdac72022-01-20 15:41:28 -0800310 // fd was not cached or cached fd can't be used
Yifan Hong53e0deb2019-03-22 17:01:08 -0700311 std::string tasks_path = controller()->GetTasksFilePath(path_);
Suren Baghdasaryanbee9f572019-02-05 16:44:22 -0800312 unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(tasks_path.c_str(), O_WRONLY | O_CLOEXEC)));
313 if (tmp_fd < 0) {
Rick Yiud4c53512021-11-21 15:57:36 +0800314 PLOG(WARNING) << "Failed to open " << tasks_path;
Suren Baghdasaryan8a315d22019-02-14 14:40:41 -0800315 return false;
Suren Baghdasaryanbee9f572019-02-05 16:44:22 -0800316 }
Suren Baghdasaryanec885562021-09-02 19:47:12 -0700317 if (!AddTidToCgroup(tid, tmp_fd, controller()->name())) {
Wei Wangd71d3012019-03-07 11:59:12 -0800318 LOG(ERROR) << "Failed to add task into cgroup";
Suren Baghdasaryanbee9f572019-02-05 16:44:22 -0800319 return false;
320 }
321
322 return true;
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800323}
324
Suren Baghdasaryanf3bdac72022-01-20 15:41:28 -0800325void SetCgroupAction::EnableResourceCaching(ResourceCacheType cache_type) {
Suren Baghdasaryanc2ee2e52022-01-20 10:58:43 -0800326 std::lock_guard<std::mutex> lock(fd_mutex_);
Suren Baghdasaryanf3bdac72022-01-20 15:41:28 -0800327 // Return early to prevent unnecessary calls to controller_.Get{Tasks|Procs}FilePath() which
328 // include regex evaluations
329 if (fd_[cache_type] != FdCacheHelper::FDS_NOT_CACHED) {
330 return;
331 }
332 switch (cache_type) {
333 case (ProfileAction::RCT_TASK):
334 FdCacheHelper::Cache(controller_.GetTasksFilePath(path_), fd_[cache_type]);
335 break;
336 case (ProfileAction::RCT_PROCESS):
337 // uid and pid don't matter because IsAppDependentPath ensures the path doesn't use them
338 FdCacheHelper::Cache(controller_.GetProcsFilePath(path_, 0, 0), fd_[cache_type]);
339 break;
340 default:
341 LOG(ERROR) << "Invalid cache type is specified!";
342 break;
343 }
Suren Baghdasaryanc2ee2e52022-01-20 10:58:43 -0800344}
345
Suren Baghdasaryanf3bdac72022-01-20 15:41:28 -0800346void SetCgroupAction::DropResourceCaching(ResourceCacheType cache_type) {
Suren Baghdasaryanc2ee2e52022-01-20 10:58:43 -0800347 std::lock_guard<std::mutex> lock(fd_mutex_);
Suren Baghdasaryanf3bdac72022-01-20 15:41:28 -0800348 FdCacheHelper::Drop(fd_[cache_type]);
Suren Baghdasaryanc2ee2e52022-01-20 10:58:43 -0800349}
350
Rick Yiud4c53512021-11-21 15:57:36 +0800351WriteFileAction::WriteFileAction(const std::string& path, const std::string& value,
352 bool logfailures)
353 : path_(path), value_(value), logfailures_(logfailures) {
Suren Baghdasaryanc2ee2e52022-01-20 10:58:43 -0800354 FdCacheHelper::Init(path_, fd_);
Rick Yiud4c53512021-11-21 15:57:36 +0800355}
Rick Yiubc1ad962020-10-26 20:32:52 +0800356
Rick Yiud4c53512021-11-21 15:57:36 +0800357bool WriteFileAction::WriteValueToFile(const std::string& value, const std::string& path,
358 bool logfailures) {
359 // Use WriteStringToFd instead of WriteStringToFile because the latter will open file with
360 // O_TRUNC which causes kernfs_mutex contention
361 unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_WRONLY | O_CLOEXEC)));
Rick Yiubc1ad962020-10-26 20:32:52 +0800362
Rick Yiud4c53512021-11-21 15:57:36 +0800363 if (tmp_fd < 0) {
364 if (logfailures) PLOG(WARNING) << "Failed to open " << path;
365 return false;
366 }
367
368 if (!WriteStringToFd(value, tmp_fd)) {
369 if (logfailures) PLOG(ERROR) << "Failed to write '" << value << "' to " << path;
Rick Yiubc1ad962020-10-26 20:32:52 +0800370 return false;
371 }
372
373 return true;
374}
375
Suren Baghdasaryanf3bdac72022-01-20 15:41:28 -0800376ProfileAction::CacheUseResult WriteFileAction::UseCachedFd(ResourceCacheType cache_type,
377 const std::string& value) const {
Rick Yiud4c53512021-11-21 15:57:36 +0800378 std::lock_guard<std::mutex> lock(fd_mutex_);
Suren Baghdasaryanf3bdac72022-01-20 15:41:28 -0800379 if (FdCacheHelper::IsCached(fd_)) {
380 // fd is cached, reuse it
381 if (!WriteStringToFd(value, fd_)) {
382 if (logfailures_) PLOG(ERROR) << "Failed to write '" << value << "' to " << path_;
383 return ProfileAction::FAIL;
384 }
385 return ProfileAction::SUCCESS;
386 }
387
388 if (fd_ == FdCacheHelper::FDS_INACCESSIBLE) {
389 // no permissions to access the file, ignore
390 return ProfileAction::SUCCESS;
391 }
392
393 if (cache_type == ResourceCacheType::RCT_TASK && fd_ == FdCacheHelper::FDS_APP_DEPENDENT) {
394 // application-dependent path can't be used with tid
395 PLOG(ERROR) << "Application profile can't be applied to a thread";
396 return ProfileAction::FAIL;
397 }
398 return ProfileAction::UNUSED;
399}
400
401bool WriteFileAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
Rick Yiud4c53512021-11-21 15:57:36 +0800402 std::string value(value_);
Rick Yiud4c53512021-11-21 15:57:36 +0800403
404 value = StringReplace(value, "<uid>", std::to_string(uid), true);
405 value = StringReplace(value, "<pid>", std::to_string(pid), true);
Suren Baghdasaryanf3bdac72022-01-20 15:41:28 -0800406
407 CacheUseResult result = UseCachedFd(ProfileAction::RCT_PROCESS, value);
408 if (result != ProfileAction::UNUSED) {
409 return result == ProfileAction::SUCCESS;
410 }
411
412 std::string path(path_);
Rick Yiud4c53512021-11-21 15:57:36 +0800413 path = StringReplace(path, "<uid>", std::to_string(uid), true);
414 path = StringReplace(path, "<pid>", std::to_string(pid), true);
415
416 return WriteValueToFile(value, path, logfailures_);
417}
418
Rick Yiubc1ad962020-10-26 20:32:52 +0800419bool WriteFileAction::ExecuteForTask(int tid) const {
Rick Yiud4c53512021-11-21 15:57:36 +0800420 std::string value(value_);
Rick Yiubc1ad962020-10-26 20:32:52 +0800421 int uid = getuid();
422
Rick Yiubc1ad962020-10-26 20:32:52 +0800423 value = StringReplace(value, "<uid>", std::to_string(uid), true);
424 value = StringReplace(value, "<pid>", std::to_string(tid), true);
425
Suren Baghdasaryanf3bdac72022-01-20 15:41:28 -0800426 CacheUseResult result = UseCachedFd(ProfileAction::RCT_TASK, value);
427 if (result != ProfileAction::UNUSED) {
428 return result == ProfileAction::SUCCESS;
Rick Yiubc1ad962020-10-26 20:32:52 +0800429 }
430
Rick Yiud4c53512021-11-21 15:57:36 +0800431 return WriteValueToFile(value, path_, logfailures_);
Rick Yiubc1ad962020-10-26 20:32:52 +0800432}
433
Suren Baghdasaryanf3bdac72022-01-20 15:41:28 -0800434void WriteFileAction::EnableResourceCaching(ResourceCacheType) {
Suren Baghdasaryanc2ee2e52022-01-20 10:58:43 -0800435 std::lock_guard<std::mutex> lock(fd_mutex_);
436 FdCacheHelper::Cache(path_, fd_);
437}
438
Suren Baghdasaryanf3bdac72022-01-20 15:41:28 -0800439void WriteFileAction::DropResourceCaching(ResourceCacheType) {
Suren Baghdasaryanc2ee2e52022-01-20 10:58:43 -0800440 std::lock_guard<std::mutex> lock(fd_mutex_);
441 FdCacheHelper::Drop(fd_);
442}
443
Rick Yiu0b211fa2019-09-16 19:07:17 +0800444bool ApplyProfileAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
445 for (const auto& profile : profiles_) {
Suren Baghdasaryanf3bdac72022-01-20 15:41:28 -0800446 profile->ExecuteForProcess(uid, pid);
Rick Yiu0b211fa2019-09-16 19:07:17 +0800447 }
448 return true;
449}
450
451bool ApplyProfileAction::ExecuteForTask(int tid) const {
452 for (const auto& profile : profiles_) {
Wei Wang8722e4d2021-05-14 12:34:54 -0700453 profile->ExecuteForTask(tid);
Rick Yiu0b211fa2019-09-16 19:07:17 +0800454 }
455 return true;
456}
457
Suren Baghdasaryanf3bdac72022-01-20 15:41:28 -0800458void ApplyProfileAction::EnableResourceCaching(ResourceCacheType cache_type) {
Suren Baghdasaryan911109c2020-02-13 17:28:00 -0800459 for (const auto& profile : profiles_) {
Suren Baghdasaryanf3bdac72022-01-20 15:41:28 -0800460 profile->EnableResourceCaching(cache_type);
Suren Baghdasaryan911109c2020-02-13 17:28:00 -0800461 }
462}
463
Suren Baghdasaryanf3bdac72022-01-20 15:41:28 -0800464void ApplyProfileAction::DropResourceCaching(ResourceCacheType cache_type) {
Suren Baghdasaryan911109c2020-02-13 17:28:00 -0800465 for (const auto& profile : profiles_) {
Suren Baghdasaryanf3bdac72022-01-20 15:41:28 -0800466 profile->DropResourceCaching(cache_type);
Suren Baghdasaryan911109c2020-02-13 17:28:00 -0800467 }
468}
469
Suren Baghdasaryan84385952020-01-24 16:36:10 -0800470void TaskProfile::MoveTo(TaskProfile* profile) {
471 profile->elements_ = std::move(elements_);
472 profile->res_cached_ = res_cached_;
473}
474
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800475bool TaskProfile::ExecuteForProcess(uid_t uid, pid_t pid) const {
476 for (const auto& element : elements_) {
477 if (!element->ExecuteForProcess(uid, pid)) {
478 return false;
479 }
480 }
481 return true;
482}
483
484bool TaskProfile::ExecuteForTask(int tid) const {
485 if (tid == 0) {
486 tid = GetThreadId();
487 }
488 for (const auto& element : elements_) {
489 if (!element->ExecuteForTask(tid)) {
490 return false;
491 }
492 }
493 return true;
494}
495
Suren Baghdasaryanf3bdac72022-01-20 15:41:28 -0800496void TaskProfile::EnableResourceCaching(ProfileAction::ResourceCacheType cache_type) {
Suren Baghdasaryan8a315d22019-02-14 14:40:41 -0800497 if (res_cached_) {
498 return;
499 }
500
501 for (auto& element : elements_) {
Suren Baghdasaryanf3bdac72022-01-20 15:41:28 -0800502 element->EnableResourceCaching(cache_type);
Suren Baghdasaryan8a315d22019-02-14 14:40:41 -0800503 }
504
505 res_cached_ = true;
506}
507
Suren Baghdasaryanf3bdac72022-01-20 15:41:28 -0800508void TaskProfile::DropResourceCaching(ProfileAction::ResourceCacheType cache_type) {
Riddle Hsua6abd822019-06-18 15:53:53 -0600509 if (!res_cached_) {
510 return;
511 }
512
513 for (auto& element : elements_) {
Suren Baghdasaryanf3bdac72022-01-20 15:41:28 -0800514 element->DropResourceCaching(cache_type);
Riddle Hsua6abd822019-06-18 15:53:53 -0600515 }
516
517 res_cached_ = false;
518}
519
Suren Baghdasaryanf3bdac72022-01-20 15:41:28 -0800520void TaskProfiles::DropResourceCaching(ProfileAction::ResourceCacheType cache_type) const {
Riddle Hsua6abd822019-06-18 15:53:53 -0600521 for (auto& iter : profiles_) {
Suren Baghdasaryanf3bdac72022-01-20 15:41:28 -0800522 iter.second->DropResourceCaching(cache_type);
Riddle Hsua6abd822019-06-18 15:53:53 -0600523 }
524}
525
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800526TaskProfiles& TaskProfiles::GetInstance() {
Peter Collingbournedba6d442019-03-20 21:09:46 -0700527 // Deliberately leak this object to avoid a race between destruction on
528 // process exit and concurrent access from another thread.
529 static auto* instance = new TaskProfiles;
530 return *instance;
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800531}
532
533TaskProfiles::TaskProfiles() {
Suren Baghdasaryan756a6042020-12-03 11:38:42 -0800534 // load system task profiles
535 if (!Load(CgroupMap::GetInstance(), TASK_PROFILE_DB_FILE)) {
536 LOG(ERROR) << "Loading " << TASK_PROFILE_DB_FILE << " for [" << getpid() << "] failed";
537 }
Suren Baghdasaryan35221b52020-11-20 17:08:51 -0800538
539 // load API-level specific system task profiles if available
Suren Baghdasaryan756a6042020-12-03 11:38:42 -0800540 unsigned int api_level = GetUintProperty<unsigned int>("ro.product.first_api_level", 0);
Suren Baghdasaryan35221b52020-11-20 17:08:51 -0800541 if (api_level > 0) {
542 std::string api_profiles_path =
543 android::base::StringPrintf(TEMPLATE_TASK_PROFILE_API_FILE, api_level);
544 if (!access(api_profiles_path.c_str(), F_OK) || errno != ENOENT) {
Suren Baghdasaryan756a6042020-12-03 11:38:42 -0800545 if (!Load(CgroupMap::GetInstance(), api_profiles_path)) {
Suren Baghdasaryanc2ee2e52022-01-20 10:58:43 -0800546 LOG(ERROR) << "Loading " << api_profiles_path << " for [" << getpid() << "] failed";
Suren Baghdasaryan756a6042020-12-03 11:38:42 -0800547 }
Suren Baghdasaryan35221b52020-11-20 17:08:51 -0800548 }
549 }
550
Suren Baghdasaryan05da67c2019-02-19 15:01:28 -0800551 // load vendor task profiles if the file exists
552 if (!access(TASK_PROFILE_DB_VENDOR_FILE, F_OK) &&
553 !Load(CgroupMap::GetInstance(), TASK_PROFILE_DB_VENDOR_FILE)) {
554 LOG(ERROR) << "Loading " << TASK_PROFILE_DB_VENDOR_FILE << " for [" << getpid()
555 << "] failed";
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800556 }
557}
558
Suren Baghdasaryan05da67c2019-02-19 15:01:28 -0800559bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) {
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800560 std::string json_doc;
561
Suren Baghdasaryan05da67c2019-02-19 15:01:28 -0800562 if (!android::base::ReadFileToString(file_name, &json_doc)) {
563 LOG(ERROR) << "Failed to read task profiles from " << file_name;
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800564 return false;
565 }
566
Haibo Huangd9ac92a2021-02-24 17:34:50 -0800567 Json::CharReaderBuilder builder;
568 std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800569 Json::Value root;
Haibo Huangd9ac92a2021-02-24 17:34:50 -0800570 std::string errorMessage;
571 if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), &root, &errorMessage)) {
572 LOG(ERROR) << "Failed to parse task profiles: " << errorMessage;
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800573 return false;
574 }
575
Suren Baghdasaryane681df42019-02-20 16:17:22 -0800576 const Json::Value& attr = root["Attributes"];
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800577 for (Json::Value::ArrayIndex i = 0; i < attr.size(); ++i) {
578 std::string name = attr[i]["Name"].asString();
Suren Baghdasaryan05da67c2019-02-19 15:01:28 -0800579 std::string controller_name = attr[i]["Controller"].asString();
580 std::string file_attr = attr[i]["File"].asString();
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800581
Suren Baghdasaryan81b9f0b2020-07-01 12:34:17 -0700582 auto controller = cg_map.FindController(controller_name);
583 if (controller.HasValue()) {
584 auto iter = attributes_.find(name);
585 if (iter == attributes_.end()) {
Suren Baghdasaryan05da67c2019-02-19 15:01:28 -0800586 attributes_[name] = std::make_unique<ProfileAttribute>(controller, file_attr);
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800587 } else {
Suren Baghdasaryan81b9f0b2020-07-01 12:34:17 -0700588 iter->second->Reset(controller, file_attr);
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800589 }
590 } else {
Suren Baghdasaryan81b9f0b2020-07-01 12:34:17 -0700591 LOG(WARNING) << "Controller " << controller_name << " is not found";
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800592 }
593 }
594
Suren Baghdasaryane681df42019-02-20 16:17:22 -0800595 const Json::Value& profiles_val = root["Profiles"];
596 for (Json::Value::ArrayIndex i = 0; i < profiles_val.size(); ++i) {
597 const Json::Value& profile_val = profiles_val[i];
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800598
Suren Baghdasaryane681df42019-02-20 16:17:22 -0800599 std::string profile_name = profile_val["Name"].asString();
600 const Json::Value& actions = profile_val["Actions"];
Rick Yiu0b211fa2019-09-16 19:07:17 +0800601 auto profile = std::make_shared<TaskProfile>();
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800602
Suren Baghdasaryane681df42019-02-20 16:17:22 -0800603 for (Json::Value::ArrayIndex act_idx = 0; act_idx < actions.size(); ++act_idx) {
604 const Json::Value& action_val = actions[act_idx];
605 std::string action_name = action_val["Name"].asString();
606 const Json::Value& params_val = action_val["Params"];
607 if (action_name == "JoinCgroup") {
608 std::string controller_name = params_val["Controller"].asString();
609 std::string path = params_val["Path"].asString();
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800610
Yifan Hong53e0deb2019-03-22 17:01:08 -0700611 auto controller = cg_map.FindController(controller_name);
612 if (controller.HasValue()) {
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800613 profile->Add(std::make_unique<SetCgroupAction>(controller, path));
614 } else {
Suren Baghdasaryan05da67c2019-02-19 15:01:28 -0800615 LOG(WARNING) << "JoinCgroup: controller " << controller_name << " is not found";
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800616 }
Suren Baghdasaryane681df42019-02-20 16:17:22 -0800617 } else if (action_name == "SetTimerSlack") {
618 std::string slack_value = params_val["Slack"].asString();
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800619 char* end;
620 unsigned long slack;
621
Suren Baghdasaryane681df42019-02-20 16:17:22 -0800622 slack = strtoul(slack_value.c_str(), &end, 10);
623 if (end > slack_value.c_str()) {
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800624 profile->Add(std::make_unique<SetTimerSlackAction>(slack));
625 } else {
Suren Baghdasaryane681df42019-02-20 16:17:22 -0800626 LOG(WARNING) << "SetTimerSlack: invalid parameter: " << slack_value;
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800627 }
Suren Baghdasaryane681df42019-02-20 16:17:22 -0800628 } else if (action_name == "SetAttribute") {
629 std::string attr_name = params_val["Name"].asString();
630 std::string attr_value = params_val["Value"].asString();
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800631
Suren Baghdasaryane681df42019-02-20 16:17:22 -0800632 auto iter = attributes_.find(attr_name);
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800633 if (iter != attributes_.end()) {
634 profile->Add(
Suren Baghdasaryane681df42019-02-20 16:17:22 -0800635 std::make_unique<SetAttributeAction>(iter->second.get(), attr_value));
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800636 } else {
Suren Baghdasaryane681df42019-02-20 16:17:22 -0800637 LOG(WARNING) << "SetAttribute: unknown attribute: " << attr_name;
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800638 }
Suren Baghdasaryane681df42019-02-20 16:17:22 -0800639 } else if (action_name == "SetClamps") {
640 std::string boost_value = params_val["Boost"].asString();
641 std::string clamp_value = params_val["Clamp"].asString();
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800642 char* end;
643 unsigned long boost;
644
Suren Baghdasaryane681df42019-02-20 16:17:22 -0800645 boost = strtoul(boost_value.c_str(), &end, 10);
646 if (end > boost_value.c_str()) {
647 unsigned long clamp = strtoul(clamp_value.c_str(), &end, 10);
648 if (end > clamp_value.c_str()) {
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800649 profile->Add(std::make_unique<SetClampsAction>(boost, clamp));
650 } else {
Suren Baghdasaryane681df42019-02-20 16:17:22 -0800651 LOG(WARNING) << "SetClamps: invalid parameter " << clamp_value;
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800652 }
653 } else {
Suren Baghdasaryane681df42019-02-20 16:17:22 -0800654 LOG(WARNING) << "SetClamps: invalid parameter: " << boost_value;
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800655 }
Rick Yiubc1ad962020-10-26 20:32:52 +0800656 } else if (action_name == "WriteFile") {
657 std::string attr_filepath = params_val["FilePath"].asString();
658 std::string attr_value = params_val["Value"].asString();
659 if (!attr_filepath.empty() && !attr_value.empty()) {
Rick Yiu49fce952021-04-08 22:10:06 +0800660 std::string attr_logfailures = params_val["LogFailures"].asString();
661 bool logfailures = attr_logfailures.empty() || attr_logfailures == "true";
Rick Yiud76053a2021-01-25 12:44:45 +0800662 profile->Add(std::make_unique<WriteFileAction>(attr_filepath, attr_value,
Rick Yiu49fce952021-04-08 22:10:06 +0800663 logfailures));
Rick Yiubc1ad962020-10-26 20:32:52 +0800664 } else if (attr_filepath.empty()) {
665 LOG(WARNING) << "WriteFile: invalid parameter: "
666 << "empty filepath";
667 } else if (attr_value.empty()) {
668 LOG(WARNING) << "WriteFile: invalid parameter: "
669 << "empty value";
670 }
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800671 } else {
Suren Baghdasaryane681df42019-02-20 16:17:22 -0800672 LOG(WARNING) << "Unknown profile action: " << action_name;
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800673 }
674 }
Suren Baghdasaryan84385952020-01-24 16:36:10 -0800675 auto iter = profiles_.find(profile_name);
676 if (iter == profiles_.end()) {
677 profiles_[profile_name] = profile;
678 } else {
679 // Move the content rather that replace the profile because old profile might be
680 // referenced from an aggregate profile if vendor overrides task profiles
681 profile->MoveTo(iter->second.get());
682 profile.reset();
683 }
Rick Yiu0b211fa2019-09-16 19:07:17 +0800684 }
685
686 const Json::Value& aggregateprofiles_val = root["AggregateProfiles"];
687 for (Json::Value::ArrayIndex i = 0; i < aggregateprofiles_val.size(); ++i) {
688 const Json::Value& aggregateprofile_val = aggregateprofiles_val[i];
689
690 std::string aggregateprofile_name = aggregateprofile_val["Name"].asString();
691 const Json::Value& aggregateprofiles = aggregateprofile_val["Profiles"];
692 std::vector<std::shared_ptr<TaskProfile>> profiles;
693 bool ret = true;
694
695 for (Json::Value::ArrayIndex pf_idx = 0; pf_idx < aggregateprofiles.size(); ++pf_idx) {
696 std::string profile_name = aggregateprofiles[pf_idx].asString();
697
698 if (profile_name == aggregateprofile_name) {
699 LOG(WARNING) << "AggregateProfiles: recursive profile name: " << profile_name;
700 ret = false;
701 break;
702 } else if (profiles_.find(profile_name) == profiles_.end()) {
703 LOG(WARNING) << "AggregateProfiles: undefined profile name: " << profile_name;
704 ret = false;
705 break;
706 } else {
707 profiles.push_back(profiles_[profile_name]);
708 }
709 }
710 if (ret) {
711 auto profile = std::make_shared<TaskProfile>();
712 profile->Add(std::make_unique<ApplyProfileAction>(profiles));
713 profiles_[aggregateprofile_name] = profile;
714 }
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800715 }
716
717 return true;
718}
719
Suren Baghdasaryan8a315d22019-02-14 14:40:41 -0800720TaskProfile* TaskProfiles::GetProfile(const std::string& name) const {
Suren Baghdasaryan82b72a52018-12-21 11:41:50 -0800721 auto iter = profiles_.find(name);
722
723 if (iter != profiles_.end()) {
724 return iter->second.get();
725 }
726 return nullptr;
727}
728
729const ProfileAttribute* TaskProfiles::GetAttribute(const std::string& name) const {
730 auto iter = attributes_.find(name);
731
732 if (iter != attributes_.end()) {
733 return iter->second.get();
734 }
735 return nullptr;
736}
Rick Yiu0b211fa2019-09-16 19:07:17 +0800737
738bool TaskProfiles::SetProcessProfiles(uid_t uid, pid_t pid,
Suren Baghdasaryanf3bdac72022-01-20 15:41:28 -0800739 const std::vector<std::string>& profiles, bool use_fd_cache) {
Rick Yiu0b211fa2019-09-16 19:07:17 +0800740 for (const auto& name : profiles) {
741 TaskProfile* profile = GetProfile(name);
742 if (profile != nullptr) {
Suren Baghdasaryanf3bdac72022-01-20 15:41:28 -0800743 if (use_fd_cache) {
744 profile->EnableResourceCaching(ProfileAction::RCT_PROCESS);
745 }
Rick Yiu0b211fa2019-09-16 19:07:17 +0800746 if (!profile->ExecuteForProcess(uid, pid)) {
747 PLOG(WARNING) << "Failed to apply " << name << " process profile";
748 }
749 } else {
750 PLOG(WARNING) << "Failed to find " << name << "process profile";
751 }
752 }
753 return true;
754}
755
756bool TaskProfiles::SetTaskProfiles(int tid, const std::vector<std::string>& profiles,
757 bool use_fd_cache) {
758 for (const auto& name : profiles) {
759 TaskProfile* profile = GetProfile(name);
760 if (profile != nullptr) {
761 if (use_fd_cache) {
Suren Baghdasaryanf3bdac72022-01-20 15:41:28 -0800762 profile->EnableResourceCaching(ProfileAction::RCT_TASK);
Rick Yiu0b211fa2019-09-16 19:07:17 +0800763 }
764 if (!profile->ExecuteForTask(tid)) {
765 PLOG(WARNING) << "Failed to apply " << name << " task profile";
766 }
767 } else {
768 PLOG(WARNING) << "Failed to find " << name << "task profile";
769 }
770 }
771 return true;
772}