Merge "Support process path for WriteFileAction"
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index 73aa2af..dc7c368 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -350,14 +350,33 @@
     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, const std::string& path,
-                                       bool logfailures) {
+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_;
+    }
+
     // 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)));
@@ -378,21 +397,27 @@
 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;
@@ -401,46 +426,64 @@
 }
 
 bool WriteFileAction::ExecuteForProcess(uid_t uid, pid_t pid) 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(ProfileAction::RCT_PROCESS, value);
-    if (result != ProfileAction::UNUSED) {
-        return result == ProfileAction::SUCCESS;
+    if (!proc_path_.empty()) {
+        return WriteValueToFile(value_, ProfileAction::RCT_PROCESS, uid, pid, logfailures_);
     }
 
-    std::string path(path_);
-    path = StringReplace(path, "<uid>", std::to_string(uid), true);
-    path = StringReplace(path, "<pid>", std::to_string(pid), true);
+    DIR* d;
+    struct dirent* de;
+    char proc_path[255];
+    int t_pid;
 
-    return WriteValueToFile(value, path, logfailures_);
+    sprintf(proc_path, "/proc/%d/task", pid);
+    if (!(d = opendir(proc_path))) {
+        return false;
+    }
+
+    while ((de = readdir(d))) {
+        if (de->d_name[0] == '.') {
+            continue;
+        }
+
+        t_pid = atoi(de->d_name);
+
+        if (!t_pid) {
+            continue;
+        }
+
+        WriteValueToFile(value_, ProfileAction::RCT_TASK, uid, t_pid, logfailures_);
+    }
+
+    closedir(d);
+
+    return true;
 }
 
 bool WriteFileAction::ExecuteForTask(int tid) const {
-    std::string value(value_);
-    int uid = getuid();
+    return WriteValueToFile(value_, ProfileAction::RCT_TASK, getuid(), tid, logfailures_);
+}
 
-    value = StringReplace(value, "<uid>", std::to_string(uid), true);
-    value = StringReplace(value, "<pid>", std::to_string(tid), true);
-
-    CacheUseResult result = UseCachedFd(ProfileAction::RCT_TASK, value);
-    if (result != ProfileAction::UNUSED) {
-        return result == ProfileAction::SUCCESS;
+void WriteFileAction::EnableResourceCaching(ResourceCacheType cache_type) {
+    std::lock_guard<std::mutex> lock(fd_mutex_);
+    if (fd_[cache_type] != FdCacheHelper::FDS_NOT_CACHED) {
+        return;
     }
-
-    return WriteValueToFile(value, path_, logfailures_);
+    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::EnableResourceCaching(ResourceCacheType) {
+void WriteFileAction::DropResourceCaching(ResourceCacheType cache_type) {
     std::lock_guard<std::mutex> lock(fd_mutex_);
-    FdCacheHelper::Cache(path_, fd_);
-}
-
-void WriteFileAction::DropResourceCaching(ResourceCacheType) {
-    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 {
@@ -659,12 +702,14 @@
                 }
             } 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";
diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h
index e6e65fb..9ee3781 100644
--- a/libprocessgroup/task_profiles.h
+++ b/libprocessgroup/task_profiles.h
@@ -140,7 +140,8 @@
 // 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;
@@ -149,13 +150,13 @@
     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;
 };