libprocessgroup: Use WriteStringToFd for WriteFileAction

Using WriteStringToFile will hold kernfs_mutex which is a big lock,
so use WriteStringToFd instead. Besides, also support fd cache for it.

Bug: 206970384
Test: build pass
Change-Id: Id79f9e1095f52079393c58edb9a4d526f4cc6b5e
diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h
index 97c38f4..278892d 100644
--- a/libprocessgroup/task_profiles.h
+++ b/libprocessgroup/task_profiles.h
@@ -108,50 +108,67 @@
     std::string value_;
 };
 
-// Set cgroup profile element
-class SetCgroupAction : public ProfileAction {
+// Abstract profile element for cached fd
+class CachedFdProfileAction : 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_; }
-    std::string path() const { return path_; }
-
-  private:
+  protected:
     enum FdState {
         FDS_INACCESSIBLE = -1,
         FDS_APP_DEPENDENT = -2,
         FDS_NOT_CACHED = -3,
     };
 
-    CgroupController controller_;
-    std::string path_;
     android::base::unique_fd fd_;
     mutable std::mutex fd_mutex_;
 
     static bool IsAppDependentPath(const std::string& path);
-    static bool AddTidToCgroup(int tid, int fd, const char* controller_name);
 
+    void InitFd(const std::string& path);
     bool IsFdValid() const { return fd_ > FDS_INACCESSIBLE; }
+
+    virtual const std::string GetPath() const = 0;
 };
 
-// Write to file action
-class WriteFileAction : public ProfileAction {
+// Set cgroup profile element
+class SetCgroupAction : public CachedFdProfileAction {
   public:
-    WriteFileAction(const std::string& filepath, const std::string& value,
-                    bool logfailures) noexcept
-        : filepath_(filepath), value_(value), logfailures_(logfailures) {}
+    SetCgroupAction(const CgroupController& c, const std::string& p);
 
     virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
     virtual bool ExecuteForTask(int tid) const;
 
+    const CgroupController* controller() const { return &controller_; }
+
+  protected:
+    const std::string GetPath() const override { return controller_.GetTasksFilePath(path_); }
+
   private:
-    std::string filepath_, value_;
+    CgroupController controller_;
+    std::string path_;
+
+    static bool AddTidToCgroup(int tid, int fd, const char* controller_name);
+};
+
+// Write to file action
+class WriteFileAction : public CachedFdProfileAction {
+  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_; }
+
+  private:
+    std::string path_, value_;
     bool logfailures_;
+
+    static bool WriteValueToFile(const std::string& value, const std::string& path,
+                                 bool logfailures);
 };
 
 class TaskProfile {