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 // Set cgroup profile element
112 class SetCgroupAction : public ProfileAction {
113   public:
114     SetCgroupAction(const CgroupController& c, const std::string& p);
115 
116     virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
117     virtual bool ExecuteForTask(int tid) const;
118     virtual void EnableResourceCaching();
119     virtual void DropResourceCaching();
120 
controller()121     const CgroupController* controller() const { return &controller_; }
path()122     std::string path() const { return path_; }
123 
124   private:
125     enum FdState {
126         FDS_INACCESSIBLE = -1,
127         FDS_APP_DEPENDENT = -2,
128         FDS_NOT_CACHED = -3,
129     };
130 
131     CgroupController controller_;
132     std::string path_;
133     android::base::unique_fd fd_;
134     mutable std::mutex fd_mutex_;
135 
136     static bool IsAppDependentPath(const std::string& path);
137     static bool AddTidToCgroup(int tid, int fd);
138 
IsFdValid()139     bool IsFdValid() const { return fd_ > FDS_INACCESSIBLE; }
140 };
141 
142 class TaskProfile {
143   public:
TaskProfile()144     TaskProfile() : res_cached_(false) {}
145 
Add(std::unique_ptr<ProfileAction> e)146     void Add(std::unique_ptr<ProfileAction> e) { elements_.push_back(std::move(e)); }
147     void MoveTo(TaskProfile* profile);
148 
149     bool ExecuteForProcess(uid_t uid, pid_t pid) const;
150     bool ExecuteForTask(int tid) const;
151     void EnableResourceCaching();
152     void DropResourceCaching();
153 
154   private:
155     bool res_cached_;
156     std::vector<std::unique_ptr<ProfileAction>> elements_;
157 };
158 
159 // Set aggregate profile element
160 class ApplyProfileAction : public ProfileAction {
161   public:
ApplyProfileAction(const std::vector<std::shared_ptr<TaskProfile>> & profiles)162     ApplyProfileAction(const std::vector<std::shared_ptr<TaskProfile>>& profiles)
163         : profiles_(profiles) {}
164 
165     virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
166     virtual bool ExecuteForTask(int tid) const;
167     virtual void EnableResourceCaching();
168     virtual void DropResourceCaching();
169 
170   private:
171     std::vector<std::shared_ptr<TaskProfile>> profiles_;
172 };
173 
174 class TaskProfiles {
175   public:
176     // Should be used by all users
177     static TaskProfiles& GetInstance();
178 
179     TaskProfile* GetProfile(const std::string& name) const;
180     const ProfileAttribute* GetAttribute(const std::string& name) const;
181     void DropResourceCaching() const;
182     bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles);
183     bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache);
184 
185   private:
186     std::map<std::string, std::shared_ptr<TaskProfile>> profiles_;
187     std::map<std::string, std::unique_ptr<ProfileAttribute>> attributes_;
188 
189     TaskProfiles();
190 
191     bool Load(const CgroupMap& cg_map, const std::string& file_name);
192 };
193