• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 #pragma once
18 
19 #include <sys/cdefs.h>
20 #include <sys/types.h>
21 #include <functional>
22 #include <map>
23 #include <mutex>
24 #include <span>
25 #include <string>
26 #include <string_view>
27 #include <vector>
28 
29 #include <android-base/unique_fd.h>
30 #include <cgroup_map.h>
31 
32 class IProfileAttribute {
33   public:
34     virtual ~IProfileAttribute() = 0;
35     virtual void Reset(const CgroupController& controller, const std::string& file_name,
36                        const std::string& file_v2_name) = 0;
37     virtual const CgroupController* controller() const = 0;
38     virtual const std::string& file_name() const = 0;
39     virtual bool GetPathForProcess(uid_t uid, pid_t pid, std::string* path) const = 0;
40     virtual bool GetPathForTask(int tid, std::string* path) const = 0;
41     virtual bool GetPathForUID(uid_t uid, std::string* path) const = 0;
42 };
43 
44 class ProfileAttribute : public IProfileAttribute {
45   public:
46     // Cgroup attributes may have different names in the v1 and v2 hierarchies. If `file_v2_name` is
47     // not empty, `file_name` is the name for the v1 hierarchy and `file_v2_name` is the name for
48     // the v2 hierarchy. If `file_v2_name` is empty, `file_name` is used for both hierarchies.
ProfileAttribute(const CgroupController & controller,const std::string & file_name,const std::string & file_v2_name)49     ProfileAttribute(const CgroupController& controller, const std::string& file_name,
50                      const std::string& file_v2_name)
51         : controller_(controller), file_name_(file_name), file_v2_name_(file_v2_name) {}
52     ~ProfileAttribute() = default;
53 
controller()54     const CgroupController* controller() const override { return &controller_; }
55     const std::string& file_name() const override;
56     void Reset(const CgroupController& controller, const std::string& file_name,
57                const std::string& file_v2_name) override;
58 
59     bool GetPathForProcess(uid_t uid, pid_t pid, std::string* path) const override;
60     bool GetPathForTask(int tid, std::string* path) const override;
61     bool GetPathForUID(uid_t uid, std::string* path) const override;
62 
63   private:
64     CgroupController controller_;
65     std::string file_name_;
66     std::string file_v2_name_;
67 };
68 
69 // Abstract profile element
70 class ProfileAction {
71   public:
72     enum ResourceCacheType { RCT_TASK = 0, RCT_PROCESS, RCT_COUNT };
73 
~ProfileAction()74     virtual ~ProfileAction() {}
75 
76     virtual const char* Name() const = 0;
77 
78     // Default implementations will fail
ExecuteForProcess(uid_t,pid_t)79     virtual bool ExecuteForProcess(uid_t, pid_t) const { return false; }
ExecuteForTask(int)80     virtual bool ExecuteForTask(int) const { return false; }
ExecuteForUID(uid_t)81     virtual bool ExecuteForUID(uid_t) const { return false; }
82 
EnableResourceCaching(ResourceCacheType)83     virtual void EnableResourceCaching(ResourceCacheType) {}
DropResourceCaching(ResourceCacheType)84     virtual void DropResourceCaching(ResourceCacheType) {}
IsValidForProcess(uid_t uid,pid_t pid)85     virtual bool IsValidForProcess(uid_t uid, pid_t pid) const { return false; }
IsValidForTask(int tid)86     virtual bool IsValidForTask(int tid) const { return false; }
87 
88   protected:
89     enum CacheUseResult { SUCCESS, FAIL, UNUSED };
90 };
91 
92 // Profile actions
93 class SetClampsAction : public ProfileAction {
94   public:
SetClampsAction(int boost,int clamp)95     SetClampsAction(int boost, int clamp) noexcept : boost_(boost), clamp_(clamp) {}
96 
Name()97     const char* Name() const override { return "SetClamps"; }
98     bool ExecuteForProcess(uid_t uid, pid_t pid) const override;
99     bool ExecuteForTask(int tid) const override;
100 
101   protected:
102     int boost_;
103     int clamp_;
104 };
105 
106 class SetTimerSlackAction : public ProfileAction {
107   public:
SetTimerSlackAction(unsigned long slack)108     SetTimerSlackAction(unsigned long slack) noexcept : slack_(slack) {}
109 
Name()110     const char* Name() const override { return "SetTimerSlack"; }
111     bool ExecuteForTask(int tid) const override;
IsValidForProcess(uid_t uid,pid_t pid)112     bool IsValidForProcess(uid_t uid, pid_t pid) const override { return true; }
IsValidForTask(int tid)113     bool IsValidForTask(int tid) const override { return true; }
114 
115   private:
116     unsigned long slack_;
117 
118     static bool IsTimerSlackSupported(int tid);
119 };
120 
121 // Set attribute profile element
122 class SetAttributeAction : public ProfileAction {
123   public:
SetAttributeAction(const IProfileAttribute * attribute,const std::string & value,bool optional)124     SetAttributeAction(const IProfileAttribute* attribute, const std::string& value, bool optional)
125         : attribute_(attribute), value_(value), optional_(optional) {}
126 
Name()127     const char* Name() const override { return "SetAttribute"; }
128     bool ExecuteForProcess(uid_t uid, pid_t pid) const override;
129     bool ExecuteForTask(int tid) const override;
130     bool ExecuteForUID(uid_t uid) const override;
131     bool IsValidForProcess(uid_t uid, pid_t pid) const override;
132     bool IsValidForTask(int tid) const override;
133 
134   private:
135     const IProfileAttribute* attribute_;
136     std::string value_;
137     bool optional_;
138 
139     bool WriteValueToFile(const std::string& path) const;
140 };
141 
142 // Set cgroup profile element
143 class SetCgroupAction : public ProfileAction {
144   public:
145     SetCgroupAction(const CgroupController& c, const std::string& p);
146 
Name()147     const char* Name() const override { return "SetCgroup"; }
148     bool ExecuteForProcess(uid_t uid, pid_t pid) const override;
149     bool ExecuteForTask(int tid) const override;
150     void EnableResourceCaching(ResourceCacheType cache_type) override;
151     void DropResourceCaching(ResourceCacheType cache_type) override;
152     bool IsValidForProcess(uid_t uid, pid_t pid) const override;
153     bool IsValidForTask(int tid) const override;
154 
controller()155     const CgroupController* controller() const { return &controller_; }
156 
157   private:
158     CgroupController controller_;
159     std::string path_;
160     android::base::unique_fd fd_[ProfileAction::RCT_COUNT];
161     mutable std::mutex fd_mutex_;
162 
163     static bool AddTidToCgroup(int tid, int fd, const char* controller_name);
164     CacheUseResult UseCachedFd(ResourceCacheType cache_type, int id) const;
165 };
166 
167 // Write to file action
168 class WriteFileAction : public ProfileAction {
169   public:
170     WriteFileAction(const std::string& task_path, const std::string& proc_path,
171                     const std::string& value, bool logfailures);
172 
Name()173     const char* Name() const override { return "WriteFile"; }
174     bool ExecuteForProcess(uid_t uid, pid_t pid) const override;
175     bool ExecuteForTask(int tid) const override;
176     void EnableResourceCaching(ResourceCacheType cache_type) override;
177     void DropResourceCaching(ResourceCacheType cache_type) override;
178     bool IsValidForProcess(uid_t uid, pid_t pid) const override;
179     bool IsValidForTask(int tid) const override;
180 
181   private:
182     std::string task_path_, proc_path_, value_;
183     bool logfailures_;
184     android::base::unique_fd fd_[ProfileAction::RCT_COUNT];
185     mutable std::mutex fd_mutex_;
186 
187     bool WriteValueToFile(const std::string& value, ResourceCacheType cache_type, int uid, int pid,
188                           bool logfailures) const;
189     CacheUseResult UseCachedFd(ResourceCacheType cache_type, const std::string& value) const;
190 };
191 
192 class TaskProfile {
193   public:
TaskProfile(const std::string & name)194     TaskProfile(const std::string& name) : name_(name), res_cached_(false) {}
195 
Name()196     const std::string& Name() const { return name_; }
Add(std::unique_ptr<ProfileAction> e)197     void Add(std::unique_ptr<ProfileAction> e) { elements_.push_back(std::move(e)); }
198     void MoveTo(TaskProfile* profile);
199 
200     bool ExecuteForProcess(uid_t uid, pid_t pid) const;
201     bool ExecuteForTask(int tid) const;
202     bool ExecuteForUID(uid_t uid) const;
203     void EnableResourceCaching(ProfileAction::ResourceCacheType cache_type);
204     void DropResourceCaching(ProfileAction::ResourceCacheType cache_type);
205     bool IsValidForProcess(uid_t uid, pid_t pid) const;
206     bool IsValidForTask(int tid) const;
207 
208   private:
209     const std::string name_;
210     bool res_cached_;
211     std::vector<std::unique_ptr<ProfileAction>> elements_;
212 };
213 
214 // Set aggregate profile element
215 class ApplyProfileAction : public ProfileAction {
216   public:
ApplyProfileAction(const std::vector<std::shared_ptr<TaskProfile>> & profiles)217     ApplyProfileAction(const std::vector<std::shared_ptr<TaskProfile>>& profiles)
218         : profiles_(profiles) {}
219 
Name()220     const char* Name() const override { return "ApplyProfileAction"; }
221     bool ExecuteForProcess(uid_t uid, pid_t pid) const override;
222     bool ExecuteForTask(int tid) const override;
223     void EnableResourceCaching(ProfileAction::ResourceCacheType cache_type) override;
224     void DropResourceCaching(ProfileAction::ResourceCacheType cache_type) override;
225     bool IsValidForProcess(uid_t uid, pid_t pid) const override;
226     bool IsValidForTask(int tid) const override;
227 
228   private:
229     std::vector<std::shared_ptr<TaskProfile>> profiles_;
230 };
231 
232 class TaskProfiles {
233   public:
234     // Should be used by all users
235     static TaskProfiles& GetInstance();
236 
237     TaskProfile* GetProfile(std::string_view name) const;
238     const IProfileAttribute* GetAttribute(std::string_view name) const;
239     void DropResourceCaching(ProfileAction::ResourceCacheType cache_type) const;
240     template <typename T>
241     bool SetProcessProfiles(uid_t uid, pid_t pid, std::span<const T> profiles, bool use_fd_cache);
242     template <typename T>
243     bool SetTaskProfiles(int tid, std::span<const T> profiles, bool use_fd_cache);
244     template <typename T>
245     bool SetUserProfiles(uid_t uid, std::span<const T> profiles, bool use_fd_cache);
246 
247   private:
248     TaskProfiles();
249 
250     bool Load(const CgroupMap& cg_map, const std::string& file_name);
251 
252     std::map<std::string, std::shared_ptr<TaskProfile>, std::less<>> profiles_;
253     std::map<std::string, std::unique_ptr<IProfileAttribute>, std::less<>> attributes_;
254 };
255