Loading libprocessgroup/task_profiles.cpp +85 −40 Original line number Diff line number Diff line Loading @@ -350,14 +350,33 @@ void SetCgroupAction::DropResourceCaching(ResourceCacheType cache_type) { FdCacheHelper::Drop(fd_[cache_type]); } WriteFileAction::WriteFileAction(const std::string& path, const std::string& value, bool logfailures) : path_(path), value_(value), logfailures_(logfailures) { FdCacheHelper::Init(path_, fd_); WriteFileAction::WriteFileAction(const std::string& task_path, const std::string& proc_path, const std::string& value, bool logfailures) : task_path_(task_path), proc_path_(proc_path), value_(value), logfailures_(logfailures) { FdCacheHelper::Init(task_path_, fd_[ProfileAction::RCT_TASK]); if (!proc_path_.empty()) FdCacheHelper::Init(proc_path_, fd_[ProfileAction::RCT_PROCESS]); } bool WriteFileAction::WriteValueToFile(const std::string& value_, ResourceCacheType cache_type, int uid, int pid, bool logfailures) const { std::string value(value_); value = StringReplace(value, "<uid>", std::to_string(uid), true); value = StringReplace(value, "<pid>", std::to_string(pid), true); CacheUseResult result = UseCachedFd(cache_type, value); if (result != ProfileAction::UNUSED) { return result == ProfileAction::SUCCESS; } std::string path; if (cache_type == ProfileAction::RCT_TASK || proc_path_.empty()) { path = task_path_; } else { path = proc_path_; } bool WriteFileAction::WriteValueToFile(const std::string& value, const std::string& path, bool logfailures) { // Use WriteStringToFd instead of WriteStringToFile because the latter will open file with // O_TRUNC which causes kernfs_mutex contention unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_WRONLY | O_CLOEXEC))); Loading @@ -378,21 +397,27 @@ bool WriteFileAction::WriteValueToFile(const std::string& value, const std::stri ProfileAction::CacheUseResult WriteFileAction::UseCachedFd(ResourceCacheType cache_type, const std::string& value) const { std::lock_guard<std::mutex> lock(fd_mutex_); if (FdCacheHelper::IsCached(fd_)) { if (FdCacheHelper::IsCached(fd_[cache_type])) { // fd is cached, reuse it if (!WriteStringToFd(value, fd_)) { if (logfailures_) PLOG(ERROR) << "Failed to write '" << value << "' to " << path_; return ProfileAction::FAIL; bool ret = WriteStringToFd(value, fd_[cache_type]); if (!ret && logfailures_) { if (cache_type == ProfileAction::RCT_TASK || proc_path_.empty()) { PLOG(ERROR) << "Failed to write '" << value << "' to " << task_path_; } else { PLOG(ERROR) << "Failed to write '" << value << "' to " << proc_path_; } return ProfileAction::SUCCESS; } return ret ? ProfileAction::SUCCESS : ProfileAction::FAIL; } if (fd_ == FdCacheHelper::FDS_INACCESSIBLE) { if (fd_[cache_type] == FdCacheHelper::FDS_INACCESSIBLE) { // no permissions to access the file, ignore return ProfileAction::SUCCESS; } if (cache_type == ResourceCacheType::RCT_TASK && fd_ == FdCacheHelper::FDS_APP_DEPENDENT) { if (cache_type == ResourceCacheType::RCT_TASK && fd_[cache_type] == FdCacheHelper::FDS_APP_DEPENDENT) { // application-dependent path can't be used with tid PLOG(ERROR) << "Application profile can't be applied to a thread"; return ProfileAction::FAIL; Loading @@ -401,46 +426,64 @@ ProfileAction::CacheUseResult WriteFileAction::UseCachedFd(ResourceCacheType cac } bool WriteFileAction::ExecuteForProcess(uid_t uid, pid_t pid) const { std::string value(value_); if (!proc_path_.empty()) { return WriteValueToFile(value_, ProfileAction::RCT_PROCESS, uid, pid, logfailures_); } value = StringReplace(value, "<uid>", std::to_string(uid), true); value = StringReplace(value, "<pid>", std::to_string(pid), true); DIR* d; struct dirent* de; char proc_path[255]; int t_pid; CacheUseResult result = UseCachedFd(ProfileAction::RCT_PROCESS, value); if (result != ProfileAction::UNUSED) { return result == ProfileAction::SUCCESS; sprintf(proc_path, "/proc/%d/task", pid); if (!(d = opendir(proc_path))) { return false; } std::string path(path_); path = StringReplace(path, "<uid>", std::to_string(uid), true); path = StringReplace(path, "<pid>", std::to_string(pid), true); while ((de = readdir(d))) { if (de->d_name[0] == '.') { continue; } return WriteValueToFile(value, path, logfailures_); t_pid = atoi(de->d_name); if (!t_pid) { continue; } bool WriteFileAction::ExecuteForTask(int tid) const { std::string value(value_); int uid = getuid(); WriteValueToFile(value_, ProfileAction::RCT_TASK, uid, t_pid, logfailures_); } value = StringReplace(value, "<uid>", std::to_string(uid), true); value = StringReplace(value, "<pid>", std::to_string(tid), true); closedir(d); CacheUseResult result = UseCachedFd(ProfileAction::RCT_TASK, value); if (result != ProfileAction::UNUSED) { return result == ProfileAction::SUCCESS; return true; } return WriteValueToFile(value, path_, logfailures_); bool WriteFileAction::ExecuteForTask(int tid) const { return WriteValueToFile(value_, ProfileAction::RCT_TASK, getuid(), tid, logfailures_); } void WriteFileAction::EnableResourceCaching(ResourceCacheType) { void WriteFileAction::EnableResourceCaching(ResourceCacheType cache_type) { std::lock_guard<std::mutex> lock(fd_mutex_); FdCacheHelper::Cache(path_, fd_); if (fd_[cache_type] != FdCacheHelper::FDS_NOT_CACHED) { return; } switch (cache_type) { case (ProfileAction::RCT_TASK): FdCacheHelper::Cache(task_path_, fd_[cache_type]); break; case (ProfileAction::RCT_PROCESS): if (!proc_path_.empty()) FdCacheHelper::Cache(proc_path_, fd_[cache_type]); break; default: LOG(ERROR) << "Invalid cache type is specified!"; break; } } void WriteFileAction::DropResourceCaching(ResourceCacheType) { void WriteFileAction::DropResourceCaching(ResourceCacheType cache_type) { std::lock_guard<std::mutex> lock(fd_mutex_); FdCacheHelper::Drop(fd_); FdCacheHelper::Drop(fd_[cache_type]); } bool ApplyProfileAction::ExecuteForProcess(uid_t uid, pid_t pid) const { Loading Loading @@ -659,12 +702,14 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) { } } else if (action_name == "WriteFile") { std::string attr_filepath = params_val["FilePath"].asString(); std::string attr_procfilepath = params_val["ProcFilePath"].asString(); std::string attr_value = params_val["Value"].asString(); // FilePath and Value are mandatory if (!attr_filepath.empty() && !attr_value.empty()) { std::string attr_logfailures = params_val["LogFailures"].asString(); bool logfailures = attr_logfailures.empty() || attr_logfailures == "true"; profile->Add(std::make_unique<WriteFileAction>(attr_filepath, attr_value, logfailures)); profile->Add(std::make_unique<WriteFileAction>(attr_filepath, attr_procfilepath, attr_value, logfailures)); } else if (attr_filepath.empty()) { LOG(WARNING) << "WriteFile: invalid parameter: " << "empty filepath"; Loading libprocessgroup/task_profiles.h +6 −5 Original line number Diff line number Diff line Loading @@ -140,7 +140,8 @@ class SetCgroupAction : public ProfileAction { // Write to file action class WriteFileAction : public ProfileAction { public: WriteFileAction(const std::string& path, const std::string& value, bool logfailures); WriteFileAction(const std::string& task_path, const std::string& proc_path, const std::string& value, bool logfailures); const char* Name() const override { return "WriteFile"; } bool ExecuteForProcess(uid_t uid, pid_t pid) const override; Loading @@ -149,13 +150,13 @@ class WriteFileAction : public ProfileAction { void DropResourceCaching(ResourceCacheType cache_type) override; private: std::string path_, value_; std::string task_path_, proc_path_, value_; bool logfailures_; android::base::unique_fd fd_; android::base::unique_fd fd_[ProfileAction::RCT_COUNT]; mutable std::mutex fd_mutex_; static bool WriteValueToFile(const std::string& value, const std::string& path, bool logfailures); bool WriteValueToFile(const std::string& value, ResourceCacheType cache_type, int uid, int pid, bool logfailures) const; CacheUseResult UseCachedFd(ResourceCacheType cache_type, const std::string& value) const; }; Loading Loading
libprocessgroup/task_profiles.cpp +85 −40 Original line number Diff line number Diff line Loading @@ -350,14 +350,33 @@ void SetCgroupAction::DropResourceCaching(ResourceCacheType cache_type) { FdCacheHelper::Drop(fd_[cache_type]); } WriteFileAction::WriteFileAction(const std::string& path, const std::string& value, bool logfailures) : path_(path), value_(value), logfailures_(logfailures) { FdCacheHelper::Init(path_, fd_); WriteFileAction::WriteFileAction(const std::string& task_path, const std::string& proc_path, const std::string& value, bool logfailures) : task_path_(task_path), proc_path_(proc_path), value_(value), logfailures_(logfailures) { FdCacheHelper::Init(task_path_, fd_[ProfileAction::RCT_TASK]); if (!proc_path_.empty()) FdCacheHelper::Init(proc_path_, fd_[ProfileAction::RCT_PROCESS]); } bool WriteFileAction::WriteValueToFile(const std::string& value_, ResourceCacheType cache_type, int uid, int pid, bool logfailures) const { std::string value(value_); value = StringReplace(value, "<uid>", std::to_string(uid), true); value = StringReplace(value, "<pid>", std::to_string(pid), true); CacheUseResult result = UseCachedFd(cache_type, value); if (result != ProfileAction::UNUSED) { return result == ProfileAction::SUCCESS; } std::string path; if (cache_type == ProfileAction::RCT_TASK || proc_path_.empty()) { path = task_path_; } else { path = proc_path_; } bool WriteFileAction::WriteValueToFile(const std::string& value, const std::string& path, bool logfailures) { // Use WriteStringToFd instead of WriteStringToFile because the latter will open file with // O_TRUNC which causes kernfs_mutex contention unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_WRONLY | O_CLOEXEC))); Loading @@ -378,21 +397,27 @@ bool WriteFileAction::WriteValueToFile(const std::string& value, const std::stri ProfileAction::CacheUseResult WriteFileAction::UseCachedFd(ResourceCacheType cache_type, const std::string& value) const { std::lock_guard<std::mutex> lock(fd_mutex_); if (FdCacheHelper::IsCached(fd_)) { if (FdCacheHelper::IsCached(fd_[cache_type])) { // fd is cached, reuse it if (!WriteStringToFd(value, fd_)) { if (logfailures_) PLOG(ERROR) << "Failed to write '" << value << "' to " << path_; return ProfileAction::FAIL; bool ret = WriteStringToFd(value, fd_[cache_type]); if (!ret && logfailures_) { if (cache_type == ProfileAction::RCT_TASK || proc_path_.empty()) { PLOG(ERROR) << "Failed to write '" << value << "' to " << task_path_; } else { PLOG(ERROR) << "Failed to write '" << value << "' to " << proc_path_; } return ProfileAction::SUCCESS; } return ret ? ProfileAction::SUCCESS : ProfileAction::FAIL; } if (fd_ == FdCacheHelper::FDS_INACCESSIBLE) { if (fd_[cache_type] == FdCacheHelper::FDS_INACCESSIBLE) { // no permissions to access the file, ignore return ProfileAction::SUCCESS; } if (cache_type == ResourceCacheType::RCT_TASK && fd_ == FdCacheHelper::FDS_APP_DEPENDENT) { if (cache_type == ResourceCacheType::RCT_TASK && fd_[cache_type] == FdCacheHelper::FDS_APP_DEPENDENT) { // application-dependent path can't be used with tid PLOG(ERROR) << "Application profile can't be applied to a thread"; return ProfileAction::FAIL; Loading @@ -401,46 +426,64 @@ ProfileAction::CacheUseResult WriteFileAction::UseCachedFd(ResourceCacheType cac } bool WriteFileAction::ExecuteForProcess(uid_t uid, pid_t pid) const { std::string value(value_); if (!proc_path_.empty()) { return WriteValueToFile(value_, ProfileAction::RCT_PROCESS, uid, pid, logfailures_); } value = StringReplace(value, "<uid>", std::to_string(uid), true); value = StringReplace(value, "<pid>", std::to_string(pid), true); DIR* d; struct dirent* de; char proc_path[255]; int t_pid; CacheUseResult result = UseCachedFd(ProfileAction::RCT_PROCESS, value); if (result != ProfileAction::UNUSED) { return result == ProfileAction::SUCCESS; sprintf(proc_path, "/proc/%d/task", pid); if (!(d = opendir(proc_path))) { return false; } std::string path(path_); path = StringReplace(path, "<uid>", std::to_string(uid), true); path = StringReplace(path, "<pid>", std::to_string(pid), true); while ((de = readdir(d))) { if (de->d_name[0] == '.') { continue; } return WriteValueToFile(value, path, logfailures_); t_pid = atoi(de->d_name); if (!t_pid) { continue; } bool WriteFileAction::ExecuteForTask(int tid) const { std::string value(value_); int uid = getuid(); WriteValueToFile(value_, ProfileAction::RCT_TASK, uid, t_pid, logfailures_); } value = StringReplace(value, "<uid>", std::to_string(uid), true); value = StringReplace(value, "<pid>", std::to_string(tid), true); closedir(d); CacheUseResult result = UseCachedFd(ProfileAction::RCT_TASK, value); if (result != ProfileAction::UNUSED) { return result == ProfileAction::SUCCESS; return true; } return WriteValueToFile(value, path_, logfailures_); bool WriteFileAction::ExecuteForTask(int tid) const { return WriteValueToFile(value_, ProfileAction::RCT_TASK, getuid(), tid, logfailures_); } void WriteFileAction::EnableResourceCaching(ResourceCacheType) { void WriteFileAction::EnableResourceCaching(ResourceCacheType cache_type) { std::lock_guard<std::mutex> lock(fd_mutex_); FdCacheHelper::Cache(path_, fd_); if (fd_[cache_type] != FdCacheHelper::FDS_NOT_CACHED) { return; } switch (cache_type) { case (ProfileAction::RCT_TASK): FdCacheHelper::Cache(task_path_, fd_[cache_type]); break; case (ProfileAction::RCT_PROCESS): if (!proc_path_.empty()) FdCacheHelper::Cache(proc_path_, fd_[cache_type]); break; default: LOG(ERROR) << "Invalid cache type is specified!"; break; } } void WriteFileAction::DropResourceCaching(ResourceCacheType) { void WriteFileAction::DropResourceCaching(ResourceCacheType cache_type) { std::lock_guard<std::mutex> lock(fd_mutex_); FdCacheHelper::Drop(fd_); FdCacheHelper::Drop(fd_[cache_type]); } bool ApplyProfileAction::ExecuteForProcess(uid_t uid, pid_t pid) const { Loading Loading @@ -659,12 +702,14 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) { } } else if (action_name == "WriteFile") { std::string attr_filepath = params_val["FilePath"].asString(); std::string attr_procfilepath = params_val["ProcFilePath"].asString(); std::string attr_value = params_val["Value"].asString(); // FilePath and Value are mandatory if (!attr_filepath.empty() && !attr_value.empty()) { std::string attr_logfailures = params_val["LogFailures"].asString(); bool logfailures = attr_logfailures.empty() || attr_logfailures == "true"; profile->Add(std::make_unique<WriteFileAction>(attr_filepath, attr_value, logfailures)); profile->Add(std::make_unique<WriteFileAction>(attr_filepath, attr_procfilepath, attr_value, logfailures)); } else if (attr_filepath.empty()) { LOG(WARNING) << "WriteFile: invalid parameter: " << "empty filepath"; Loading
libprocessgroup/task_profiles.h +6 −5 Original line number Diff line number Diff line Loading @@ -140,7 +140,8 @@ class SetCgroupAction : public ProfileAction { // Write to file action class WriteFileAction : public ProfileAction { public: WriteFileAction(const std::string& path, const std::string& value, bool logfailures); WriteFileAction(const std::string& task_path, const std::string& proc_path, const std::string& value, bool logfailures); const char* Name() const override { return "WriteFile"; } bool ExecuteForProcess(uid_t uid, pid_t pid) const override; Loading @@ -149,13 +150,13 @@ class WriteFileAction : public ProfileAction { void DropResourceCaching(ResourceCacheType cache_type) override; private: std::string path_, value_; std::string task_path_, proc_path_, value_; bool logfailures_; android::base::unique_fd fd_; android::base::unique_fd fd_[ProfileAction::RCT_COUNT]; mutable std::mutex fd_mutex_; static bool WriteValueToFile(const std::string& value, const std::string& path, bool logfailures); bool WriteValueToFile(const std::string& value, ResourceCacheType cache_type, int uid, int pid, bool logfailures) const; CacheUseResult UseCachedFd(ResourceCacheType cache_type, const std::string& value) const; }; Loading