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