Merge changes from topic "re-enable fd caching and update VNDK" into qt-dev

* changes:
  libprocessgroup: limit libprocessgroup's VNDK API surface
  Re-enable file descriptor caching and add option to skip caching
This commit is contained in:
Suren Baghdasaryan 2019-04-23 18:41:01 +00:00 committed by Android (Google) Code Review
commit bb297e9ca3
5 changed files with 98 additions and 61 deletions

View file

@ -24,16 +24,20 @@
__BEGIN_DECLS
static constexpr const char* CGROUPV2_CONTROLLER_NAME = "cgroup2";
static constexpr const char* CGROUPS_RC_PATH = "/dev/cgroup_info/cgroup.rc";
bool CgroupGetControllerPath(const std::string& cgroup_name, std::string* path);
bool CgroupGetAttributePath(const std::string& attr_name, std::string* path);
bool CgroupGetAttributePathForTask(const std::string& attr_name, int tid, std::string* path);
bool UsePerAppMemcg();
bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache = false);
bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles,
bool use_fd_cache = false);
bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles);
bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles);
#ifndef __ANDROID_VNDK__
static constexpr const char* CGROUPS_RC_PATH = "/dev/cgroup_info/cgroup.rc";
bool UsePerAppMemcg();
// Return 0 and removes the cgroup if there are no longer any processes in it.
// Returns -1 in the case of an error occurring or if there are processes still running
@ -54,4 +58,6 @@ bool setProcessGroupLimit(uid_t uid, int initialPid, int64_t limitInBytes);
void removeAllProcessGroups(void);
#endif // __ANDROID_VNDK__
__END_DECLS

View file

@ -112,12 +112,16 @@ static bool isMemoryCgroupSupported() {
return memcg_supported;
}
bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles) {
bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles,
bool use_fd_cache) {
const TaskProfiles& tp = TaskProfiles::GetInstance();
for (const auto& name : profiles) {
const TaskProfile* profile = tp.GetProfile(name);
TaskProfile* profile = tp.GetProfile(name);
if (profile != nullptr) {
if (use_fd_cache) {
profile->EnableResourceCaching();
}
if (!profile->ExecuteForProcess(uid, pid)) {
PLOG(WARNING) << "Failed to apply " << name << " process profile";
}
@ -129,12 +133,15 @@ bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& pr
return true;
}
bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles) {
bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache) {
const TaskProfiles& tp = TaskProfiles::GetInstance();
for (const auto& name : profiles) {
const TaskProfile* profile = tp.GetProfile(name);
TaskProfile* profile = tp.GetProfile(name);
if (profile != nullptr) {
if (use_fd_cache) {
profile->EnableResourceCaching();
}
if (!profile->ExecuteForTask(tid)) {
PLOG(WARNING) << "Failed to apply " << name << " task profile";
}

View file

@ -46,26 +46,34 @@ int set_cpuset_policy(int tid, SchedPolicy policy) {
switch (policy) {
case SP_BACKGROUND:
return SetTaskProfiles(tid, {"HighEnergySaving", "ProcessCapacityLow", "LowIoPriority",
"TimerSlackHigh"})
return SetTaskProfiles(tid,
{"HighEnergySaving", "ProcessCapacityLow", "LowIoPriority",
"TimerSlackHigh"},
true)
? 0
: -1;
case SP_FOREGROUND:
case SP_AUDIO_APP:
case SP_AUDIO_SYS:
return SetTaskProfiles(tid, {"HighPerformance", "ProcessCapacityHigh", "HighIoPriority",
"TimerSlackNormal"})
return SetTaskProfiles(tid,
{"HighPerformance", "ProcessCapacityHigh", "HighIoPriority",
"TimerSlackNormal"},
true)
? 0
: -1;
case SP_TOP_APP:
return SetTaskProfiles(tid, {"MaxPerformance", "ProcessCapacityMax", "MaxIoPriority",
"TimerSlackNormal"})
return SetTaskProfiles(tid,
{"MaxPerformance", "ProcessCapacityMax", "MaxIoPriority",
"TimerSlackNormal"},
true)
? 0
: -1;
case SP_SYSTEM:
return SetTaskProfiles(tid, {"ServiceCapacityLow", "TimerSlackNormal"}) ? 0 : -1;
return SetTaskProfiles(tid, {"ServiceCapacityLow", "TimerSlackNormal"}, true) ? 0 : -1;
case SP_RESTRICTED:
return SetTaskProfiles(tid, {"ServiceCapacityRestricted", "TimerSlackNormal"}) ? 0 : -1;
return SetTaskProfiles(tid, {"ServiceCapacityRestricted", "TimerSlackNormal"}, true)
? 0
: -1;
default:
break;
}
@ -126,17 +134,17 @@ int set_sched_policy(int tid, SchedPolicy policy) {
switch (policy) {
case SP_BACKGROUND:
return SetTaskProfiles(tid, {"HighEnergySaving", "TimerSlackHigh"}) ? 0 : -1;
return SetTaskProfiles(tid, {"HighEnergySaving", "TimerSlackHigh"}, true) ? 0 : -1;
case SP_FOREGROUND:
case SP_AUDIO_APP:
case SP_AUDIO_SYS:
return SetTaskProfiles(tid, {"HighPerformance", "TimerSlackNormal"}) ? 0 : -1;
return SetTaskProfiles(tid, {"HighPerformance", "TimerSlackNormal"}, true) ? 0 : -1;
case SP_TOP_APP:
return SetTaskProfiles(tid, {"MaxPerformance", "TimerSlackNormal"}) ? 0 : -1;
return SetTaskProfiles(tid, {"MaxPerformance", "TimerSlackNormal"}, true) ? 0 : -1;
case SP_RT_APP:
return SetTaskProfiles(tid, {"RealtimePerformance", "TimerSlackNormal"}) ? 0 : -1;
return SetTaskProfiles(tid, {"RealtimePerformance", "TimerSlackNormal"}, true) ? 0 : -1;
default:
return SetTaskProfiles(tid, {"TimerSlackNormal"}) ? 0 : -1;
return SetTaskProfiles(tid, {"TimerSlackNormal"}, true) ? 0 : -1;
}
return 0;

View file

@ -138,31 +138,38 @@ bool SetCgroupAction::IsAppDependentPath(const std::string& path) {
SetCgroupAction::SetCgroupAction(const CgroupController& c, const std::string& p)
: controller_(c), path_(p) {
#ifdef CACHE_FILE_DESCRIPTORS
// cache file descriptor only if path is app independent
// file descriptors for app-dependent paths can't be cached
if (IsAppDependentPath(path_)) {
// file descriptor is not cached
fd_.reset(-2);
fd_.reset(FDS_APP_DEPENDENT);
return;
}
std::string tasks_path = c.GetTasksFilePath(p);
// file descriptor can be cached later on request
fd_.reset(FDS_NOT_CACHED);
}
void SetCgroupAction::EnableResourceCaching() {
if (fd_ != FDS_NOT_CACHED) {
return;
}
std::string tasks_path = controller_.GetTasksFilePath(path_);
if (access(tasks_path.c_str(), W_OK) != 0) {
// file is not accessible
fd_.reset(-1);
fd_.reset(FDS_INACCESSIBLE);
return;
}
unique_fd fd(TEMP_FAILURE_RETRY(open(tasks_path.c_str(), O_WRONLY | O_CLOEXEC)));
if (fd < 0) {
PLOG(ERROR) << "Failed to cache fd '" << tasks_path << "'";
fd_.reset(-1);
fd_.reset(FDS_INACCESSIBLE);
return;
}
fd_ = std::move(fd);
#endif
}
bool SetCgroupAction::AddTidToCgroup(int tid, int fd) {
@ -184,8 +191,7 @@ bool SetCgroupAction::AddTidToCgroup(int tid, int fd) {
}
bool SetCgroupAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
#ifdef CACHE_FILE_DESCRIPTORS
if (fd_ >= 0) {
if (IsFdValid()) {
// fd is cached, reuse it
if (!AddTidToCgroup(pid, fd_)) {
LOG(ERROR) << "Failed to add task into cgroup";
@ -194,12 +200,12 @@ bool SetCgroupAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
return true;
}
if (fd_ == -1) {
if (fd_ == FDS_INACCESSIBLE) {
// no permissions to access the file, ignore
return true;
}
// this is app-dependent path, file descriptor is not cached
// this is app-dependent path and fd is not cached or cached fd can't be used
std::string procs_path = controller()->GetProcsFilePath(path_, uid, pid);
unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(procs_path.c_str(), O_WRONLY | O_CLOEXEC)));
if (tmp_fd < 0) {
@ -212,25 +218,10 @@ bool SetCgroupAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
}
return true;
#else
std::string procs_path = controller()->GetProcsFilePath(path_, uid, pid);
unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(procs_path.c_str(), O_WRONLY | O_CLOEXEC)));
if (tmp_fd < 0) {
// no permissions to access the file, ignore
return true;
}
if (!AddTidToCgroup(pid, tmp_fd)) {
LOG(ERROR) << "Failed to add task into cgroup";
return false;
}
return true;
#endif
}
bool SetCgroupAction::ExecuteForTask(int tid) const {
#ifdef CACHE_FILE_DESCRIPTORS
if (fd_ >= 0) {
if (IsFdValid()) {
// fd is cached, reuse it
if (!AddTidToCgroup(tid, fd_)) {
LOG(ERROR) << "Failed to add task into cgroup";
@ -239,20 +230,23 @@ bool SetCgroupAction::ExecuteForTask(int tid) const {
return true;
}
if (fd_ == -1) {
if (fd_ == FDS_INACCESSIBLE) {
// no permissions to access the file, ignore
return true;
}
// application-dependent path can't be used with tid
LOG(ERROR) << "Application profile can't be applied to a thread";
return false;
#else
if (fd_ == FDS_APP_DEPENDENT) {
// application-dependent path can't be used with tid
PLOG(ERROR) << "Application profile can't be applied to a thread";
return false;
}
// fd was not cached because cached fd can't be used
std::string tasks_path = controller()->GetTasksFilePath(path_);
unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(tasks_path.c_str(), O_WRONLY | O_CLOEXEC)));
if (tmp_fd < 0) {
// no permissions to access the file, ignore
return true;
PLOG(WARNING) << "Failed to open " << tasks_path << ": " << strerror(errno);
return false;
}
if (!AddTidToCgroup(tid, tmp_fd)) {
LOG(ERROR) << "Failed to add task into cgroup";
@ -260,7 +254,6 @@ bool SetCgroupAction::ExecuteForTask(int tid) const {
}
return true;
#endif
}
bool TaskProfile::ExecuteForProcess(uid_t uid, pid_t pid) const {
@ -284,6 +277,18 @@ bool TaskProfile::ExecuteForTask(int tid) const {
return true;
}
void TaskProfile::EnableResourceCaching() {
if (res_cached_) {
return;
}
for (auto& element : elements_) {
element->EnableResourceCaching();
}
res_cached_ = true;
}
TaskProfiles& TaskProfiles::GetInstance() {
// Deliberately leak this object to avoid a race between destruction on
// process exit and concurrent access from another thread.
@ -411,7 +416,7 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) {
return true;
}
const TaskProfile* TaskProfiles::GetProfile(const std::string& name) const {
TaskProfile* TaskProfiles::GetProfile(const std::string& name) const {
auto iter = profiles_.find(name);
if (iter != profiles_.end()) {

View file

@ -48,6 +48,8 @@ class ProfileAction {
// Default implementations will fail
virtual bool ExecuteForProcess(uid_t, pid_t) const { return false; };
virtual bool ExecuteForTask(int) const { return false; };
virtual void EnableResourceCaching() {}
};
// Profile actions
@ -110,31 +112,40 @@ class SetCgroupAction : public ProfileAction {
virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
virtual bool ExecuteForTask(int tid) const;
virtual void EnableResourceCaching();
const CgroupController* controller() const { return &controller_; }
std::string path() const { return path_; }
private:
enum FdState {
FDS_INACCESSIBLE = -1,
FDS_APP_DEPENDENT = -2,
FDS_NOT_CACHED = -3,
};
CgroupController controller_;
std::string path_;
#ifdef CACHE_FILE_DESCRIPTORS
android::base::unique_fd fd_;
#endif
static bool IsAppDependentPath(const std::string& path);
static bool AddTidToCgroup(int tid, int fd);
bool IsFdValid() const { return fd_ > FDS_INACCESSIBLE; }
};
class TaskProfile {
public:
TaskProfile() {}
TaskProfile() : res_cached_(false) {}
void Add(std::unique_ptr<ProfileAction> e) { elements_.push_back(std::move(e)); }
bool ExecuteForProcess(uid_t uid, pid_t pid) const;
bool ExecuteForTask(int tid) const;
void EnableResourceCaching();
private:
bool res_cached_;
std::vector<std::unique_ptr<ProfileAction>> elements_;
};
@ -143,7 +154,7 @@ class TaskProfiles {
// Should be used by all users
static TaskProfiles& GetInstance();
const TaskProfile* GetProfile(const std::string& name) const;
TaskProfile* GetProfile(const std::string& name) const;
const ProfileAttribute* GetAttribute(const std::string& name) const;
private: