diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp index 3834f9194..a61700cec 100644 --- a/libprocessgroup/task_profiles.cpp +++ b/libprocessgroup/task_profiles.cpp @@ -51,6 +51,67 @@ static constexpr const char* TASK_PROFILE_DB_VENDOR_FILE = "/vendor/etc/task_pro static constexpr const char* TEMPLATE_TASK_PROFILE_API_FILE = "/etc/task_profiles/task_profiles_%u.json"; +class FdCacheHelper { + public: + enum FdState { + FDS_INACCESSIBLE = -1, + FDS_APP_DEPENDENT = -2, + FDS_NOT_CACHED = -3, + }; + + static void Cache(const std::string& path, android::base::unique_fd& fd); + static void Drop(android::base::unique_fd& fd); + static void Init(const std::string& path, android::base::unique_fd& fd); + static bool IsCached(const android::base::unique_fd& fd) { return fd > FDS_INACCESSIBLE; } + + private: + static bool IsAppDependentPath(const std::string& path); +}; + +void FdCacheHelper::Init(const std::string& path, android::base::unique_fd& fd) { + // file descriptors for app-dependent paths can't be cached + if (IsAppDependentPath(path)) { + // file descriptor is not cached + fd.reset(FDS_APP_DEPENDENT); + return; + } + // file descriptor can be cached later on request + fd.reset(FDS_NOT_CACHED); +} + +void FdCacheHelper::Cache(const std::string& path, android::base::unique_fd& fd) { + if (fd != FDS_NOT_CACHED) { + return; + } + + if (access(path.c_str(), W_OK) != 0) { + // file is not accessible + fd.reset(FDS_INACCESSIBLE); + return; + } + + unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_WRONLY | O_CLOEXEC))); + if (tmp_fd < 0) { + PLOG(ERROR) << "Failed to cache fd '" << path << "'"; + fd.reset(FDS_INACCESSIBLE); + return; + } + + fd = std::move(tmp_fd); +} + +void FdCacheHelper::Drop(android::base::unique_fd& fd) { + if (fd == FDS_NOT_CACHED) { + return; + } + + fd.reset(FDS_NOT_CACHED); +} + +bool FdCacheHelper::IsAppDependentPath(const std::string& path) { + return path.find("", 0) != std::string::npos || path.find("", 0) != std::string::npos; +} + void ProfileAttribute::Reset(const CgroupController& controller, const std::string& file_name) { controller_ = controller; file_name_ = file_name; @@ -144,57 +205,9 @@ bool SetAttributeAction::ExecuteForTask(int tid) const { return true; } -void CachedFdProfileAction::EnableResourceCaching() { - std::lock_guard lock(fd_mutex_); - if (fd_ != FDS_NOT_CACHED) { - return; - } - - std::string tasks_path = GetPath(); - - if (access(tasks_path.c_str(), W_OK) != 0) { - // file is not accessible - 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(FDS_INACCESSIBLE); - return; - } - - fd_ = std::move(fd); -} - -void CachedFdProfileAction::DropResourceCaching() { - std::lock_guard lock(fd_mutex_); - if (fd_ == FDS_NOT_CACHED) { - return; - } - - fd_.reset(FDS_NOT_CACHED); -} - -bool CachedFdProfileAction::IsAppDependentPath(const std::string& path) { - return path.find("", 0) != std::string::npos || path.find("", 0) != std::string::npos; -} - -void CachedFdProfileAction::InitFd(const std::string& path) { - // file descriptors for app-dependent paths can't be cached - if (IsAppDependentPath(path)) { - // file descriptor is not cached - fd_.reset(FDS_APP_DEPENDENT); - return; - } - // file descriptor can be cached later on request - fd_.reset(FDS_NOT_CACHED); -} - SetCgroupAction::SetCgroupAction(const CgroupController& c, const std::string& p) : controller_(c), path_(p) { - InitFd(controller_.GetTasksFilePath(path_)); + FdCacheHelper::Init(controller_.GetTasksFilePath(path_), fd_); } bool SetCgroupAction::AddTidToCgroup(int tid, int fd, const char* controller_name) { @@ -249,7 +262,7 @@ bool SetCgroupAction::ExecuteForProcess(uid_t uid, pid_t pid) const { bool SetCgroupAction::ExecuteForTask(int tid) const { std::lock_guard lock(fd_mutex_); - if (IsFdValid()) { + if (FdCacheHelper::IsCached(fd_)) { // fd is cached, reuse it if (!AddTidToCgroup(tid, fd_, controller()->name())) { LOG(ERROR) << "Failed to add task into cgroup"; @@ -258,12 +271,12 @@ bool SetCgroupAction::ExecuteForTask(int tid) const { return true; } - if (fd_ == FDS_INACCESSIBLE) { + if (fd_ == FdCacheHelper::FDS_INACCESSIBLE) { // no permissions to access the file, ignore return true; } - if (fd_ == FDS_APP_DEPENDENT) { + if (fd_ == 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 false; @@ -284,10 +297,20 @@ bool SetCgroupAction::ExecuteForTask(int tid) const { return true; } +void SetCgroupAction::EnableResourceCaching() { + std::lock_guard lock(fd_mutex_); + FdCacheHelper::Cache(controller_.GetTasksFilePath(path_), fd_); +} + +void SetCgroupAction::DropResourceCaching() { + std::lock_guard lock(fd_mutex_); + FdCacheHelper::Drop(fd_); +} + WriteFileAction::WriteFileAction(const std::string& path, const std::string& value, bool logfailures) : path_(path), value_(value), logfailures_(logfailures) { - InitFd(path_); + FdCacheHelper::Init(path_, fd_); } bool WriteFileAction::WriteValueToFile(const std::string& value, const std::string& path, @@ -330,7 +353,7 @@ bool WriteFileAction::ExecuteForTask(int tid) const { value = StringReplace(value, "", std::to_string(uid), true); value = StringReplace(value, "", std::to_string(tid), true); - if (IsFdValid()) { + if (FdCacheHelper::IsCached(fd_)) { // fd is cached, reuse it if (!WriteStringToFd(value, fd_)) { if (logfailures_) PLOG(ERROR) << "Failed to write '" << value << "' to " << path_; @@ -339,12 +362,12 @@ bool WriteFileAction::ExecuteForTask(int tid) const { return true; } - if (fd_ == FDS_INACCESSIBLE) { + if (fd_ == FdCacheHelper::FDS_INACCESSIBLE) { // no permissions to access the file, ignore return true; } - if (fd_ == FDS_APP_DEPENDENT) { + if (fd_ == 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 false; @@ -353,6 +376,16 @@ bool WriteFileAction::ExecuteForTask(int tid) const { return WriteValueToFile(value, path_, logfailures_); } +void WriteFileAction::EnableResourceCaching() { + std::lock_guard lock(fd_mutex_); + FdCacheHelper::Cache(path_, fd_); +} + +void WriteFileAction::DropResourceCaching() { + std::lock_guard lock(fd_mutex_); + FdCacheHelper::Drop(fd_); +} + bool ApplyProfileAction::ExecuteForProcess(uid_t uid, pid_t pid) const { for (const auto& profile : profiles_) { if (!profile->ExecuteForProcess(uid, pid)) { @@ -457,8 +490,7 @@ TaskProfiles::TaskProfiles() { android::base::StringPrintf(TEMPLATE_TASK_PROFILE_API_FILE, api_level); if (!access(api_profiles_path.c_str(), F_OK) || errno != ENOENT) { if (!Load(CgroupMap::GetInstance(), api_profiles_path)) { - LOG(ERROR) << "Loading " << api_profiles_path << " for [" << getpid() - << "] failed"; + LOG(ERROR) << "Loading " << api_profiles_path << " for [" << getpid() << "] failed"; } } } diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h index 278892dd5..11f20a282 100644 --- a/libprocessgroup/task_profiles.h +++ b/libprocessgroup/task_profiles.h @@ -108,64 +108,42 @@ class SetAttributeAction : public ProfileAction { std::string value_; }; -// Abstract profile element for cached fd -class CachedFdProfileAction : public ProfileAction { - public: - virtual void EnableResourceCaching(); - virtual void DropResourceCaching(); - - protected: - enum FdState { - FDS_INACCESSIBLE = -1, - FDS_APP_DEPENDENT = -2, - FDS_NOT_CACHED = -3, - }; - - android::base::unique_fd fd_; - mutable std::mutex fd_mutex_; - - static bool IsAppDependentPath(const std::string& path); - - void InitFd(const std::string& path); - bool IsFdValid() const { return fd_ > FDS_INACCESSIBLE; } - - virtual const std::string GetPath() const = 0; -}; - // Set cgroup profile element -class SetCgroupAction : public CachedFdProfileAction { +class SetCgroupAction : public ProfileAction { public: SetCgroupAction(const CgroupController& c, const std::string& p); virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const; virtual bool ExecuteForTask(int tid) const; + virtual void EnableResourceCaching(); + virtual void DropResourceCaching(); const CgroupController* controller() const { return &controller_; } - protected: - const std::string GetPath() const override { return controller_.GetTasksFilePath(path_); } - private: CgroupController controller_; std::string path_; + android::base::unique_fd fd_; + mutable std::mutex fd_mutex_; static bool AddTidToCgroup(int tid, int fd, const char* controller_name); }; // Write to file action -class WriteFileAction : public CachedFdProfileAction { +class WriteFileAction : public ProfileAction { public: WriteFileAction(const std::string& path, const std::string& value, bool logfailures); virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const; virtual bool ExecuteForTask(int tid) const; - - protected: - const std::string GetPath() const override { return path_; } + virtual void EnableResourceCaching(); + virtual void DropResourceCaching(); private: std::string path_, value_; bool logfailures_; + android::base::unique_fd fd_; + mutable std::mutex fd_mutex_; static bool WriteValueToFile(const std::string& value, const std::string& path, bool logfailures);