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