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 ProfileAttribute {
30   public:
ProfileAttribute(const CgroupController & controller,const std::string & file_name)31     ProfileAttribute(const CgroupController& controller, const std::string& file_name)
32         : controller_(controller), file_name_(file_name) {}
33 
controller()34     const CgroupController* controller() const { return &controller_; }
file_name()35     const std::string& file_name() const { return file_name_; }
36     void Reset(const CgroupController& controller, const std::string& file_name);
37 
38     bool GetPathForTask(int tid, std::string* path) const;
39 
40   private:
41     CgroupController controller_;
42     std::string file_name_;
43 };
44 
45 // Abstract profile element
46 class ProfileAction {
47   public:
~ProfileAction()48     virtual ~ProfileAction() {}
49 
50     // Default implementations will fail
ExecuteForProcess(uid_t,pid_t)51     virtual bool ExecuteForProcess(uid_t, pid_t) const { return false; };
ExecuteForTask(int)52     virtual bool ExecuteForTask(int) const { return false; };
53 
EnableResourceCaching()54     virtual void EnableResourceCaching() {}
DropResourceCaching()55     virtual void DropResourceCaching() {}
56 };
57 
58 // Profile actions
59 class SetClampsAction : public ProfileAction {
60   public:
SetClampsAction(int boost,int clamp)61     SetClampsAction(int boost, int clamp) noexcept : boost_(boost), clamp_(clamp) {}
62 
63     virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
64     virtual bool ExecuteForTask(int tid) const;
65 
66   protected:
67     int boost_;
68     int clamp_;
69 };
70 
71 // To avoid issues in sdk_mac build
72 #if defined(__ANDROID__)
73 
74 class SetTimerSlackAction : public ProfileAction {
75   public:
SetTimerSlackAction(unsigned long slack)76     SetTimerSlackAction(unsigned long slack) noexcept : slack_(slack) {}
77 
78     virtual bool ExecuteForTask(int tid) const;
79 
80   private:
81     unsigned long slack_;
82 
83     static bool IsTimerSlackSupported(int tid);
84 };
85 
86 #else
87 
88 class SetTimerSlackAction : public ProfileAction {
89   public:
SetTimerSlackAction(unsigned long)90     SetTimerSlackAction(unsigned long) noexcept {}
91 
ExecuteForTask(int)92     virtual bool ExecuteForTask(int) const { return true; }
93 };
94 
95 #endif
96 
97 // Set attribute profile element
98 class SetAttributeAction : public ProfileAction {
99   public:
SetAttributeAction(const ProfileAttribute * attribute,const std::string & value)100     SetAttributeAction(const ProfileAttribute* attribute, const std::string& value)
101         : attribute_(attribute), value_(value) {}
102 
103     virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
104     virtual bool ExecuteForTask(int tid) const;
105 
106   private:
107     const ProfileAttribute* attribute_;
108     std::string value_;
109 };
110 
111 // Abstract profile element for cached fd
112 class CachedFdProfileAction : public ProfileAction {
113   public:
114     virtual void EnableResourceCaching();
115     virtual void DropResourceCaching();
116 
117   protected:
118     enum FdState {
119         FDS_INACCESSIBLE = -1,
120         FDS_APP_DEPENDENT = -2,
121         FDS_NOT_CACHED = -3,
122     };
123 
124     android::base::unique_fd fd_;
125     mutable std::mutex fd_mutex_;
126 
127     static bool IsAppDependentPath(const std::string& path);
128 
129     void InitFd(const std::string& path);
IsFdValid()130     bool IsFdValid() const { return fd_ > FDS_INACCESSIBLE; }
131 
132     virtual const std::string GetPath() const = 0;
133 };
134 
135 // Set cgroup profile element
136 class SetCgroupAction : public CachedFdProfileAction {
137   public:
138     SetCgroupAction(const CgroupController& c, const std::string& p);
139 
140     virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
141     virtual bool ExecuteForTask(int tid) const;
142 
controller()143     const CgroupController* controller() const { return &controller_; }
144 
145   protected:
GetPath()146     const std::string GetPath() const override { return controller_.GetTasksFilePath(path_); }
147 
148   private:
149     CgroupController controller_;
150     std::string path_;
151 
152     static bool AddTidToCgroup(int tid, int fd, const char* controller_name);
153 };
154 
155 // Write to file action
156 class WriteFileAction : public CachedFdProfileAction {
157   public:
158     WriteFileAction(const std::string& path, const std::string& value, bool logfailures);
159 
160     virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
161     virtual bool ExecuteForTask(int tid) const;
162 
163   protected:
GetPath()164     const std::string GetPath() const override { return path_; }
165 
166   private:
167     std::string path_, value_;
168     bool logfailures_;
169 
170     static bool WriteValueToFile(const std::string& value, const std::string& path,
171                                  bool logfailures);
172 };
173 
174 class TaskProfile {
175   public:
TaskProfile()176     TaskProfile() : res_cached_(false) {}
177 
Add(std::unique_ptr<ProfileAction> e)178     void Add(std::unique_ptr<ProfileAction> e) { elements_.push_back(std::move(e)); }
179     void MoveTo(TaskProfile* profile);
180 
181     bool ExecuteForProcess(uid_t uid, pid_t pid) const;
182     bool ExecuteForTask(int tid) const;
183     void EnableResourceCaching();
184     void DropResourceCaching();
185 
186   private:
187     bool res_cached_;
188     std::vector<std::unique_ptr<ProfileAction>> elements_;
189 };
190 
191 // Set aggregate profile element
192 class ApplyProfileAction : public ProfileAction {
193   public:
ApplyProfileAction(const std::vector<std::shared_ptr<TaskProfile>> & profiles)194     ApplyProfileAction(const std::vector<std::shared_ptr<TaskProfile>>& profiles)
195         : profiles_(profiles) {}
196 
197     virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
198     virtual bool ExecuteForTask(int tid) const;
199     virtual void EnableResourceCaching();
200     virtual void DropResourceCaching();
201 
202   private:
203     std::vector<std::shared_ptr<TaskProfile>> profiles_;
204 };
205 
206 class TaskProfiles {
207   public:
208     // Should be used by all users
209     static TaskProfiles& GetInstance();
210 
211     TaskProfile* GetProfile(const std::string& name) const;
212     const ProfileAttribute* GetAttribute(const std::string& name) const;
213     void DropResourceCaching() const;
214     bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles);
215     bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache);
216 
217   private:
218     std::map<std::string, std::shared_ptr<TaskProfile>> profiles_;
219     std::map<std::string, std::unique_ptr<ProfileAttribute>> attributes_;
220 
221     TaskProfiles();
222 
223     bool Load(const CgroupMap& cg_map, const std::string& file_name);
224 };
225