libperfmgr: add dump interface

Bug: 72071908
Test: Call added interface in powerhal and check
      lshal-debug/android.hardware.power@1.2::IPower_default.txt

(cherry picked from commit b243f99965c7f9b780854233273f9d8f9e13b39c)

Change-Id: Ib2c63d40e772c0004abc1157f523eae0a357b261
diff --git a/libperfmgr/HintManager.cc b/libperfmgr/HintManager.cc
index ee40652..ce3d125 100644
--- a/libperfmgr/HintManager.cc
+++ b/libperfmgr/HintManager.cc
@@ -81,6 +81,23 @@
     return hints;
 }
 
+void HintManager::DumpToFd(int fd) {
+    std::string header("========== Begin perfmgr nodes ==========\n"
+                       "Node Name\t"
+                       "Node Path\t"
+                       "Current Index\t"
+                       "Current Value\n");
+    if (!android::base::WriteStringToFd(header, fd)) {
+        LOG(ERROR) << "Failed to dump fd: " << fd;
+    }
+    nm_->DumpToFd(fd);
+    std::string footer("==========  End perfmgr nodes  ==========\n");
+    if (!android::base::WriteStringToFd(footer, fd)) {
+        LOG(ERROR) << "Failed to dump fd: " << fd;
+    }
+    fsync(fd);
+}
+
 std::unique_ptr<HintManager> HintManager::GetFromJSON(
     const std::string& config_path) {
     std::string json_doc;
diff --git a/libperfmgr/Node.cc b/libperfmgr/Node.cc
index 6b24e9f..5367770 100644
--- a/libperfmgr/Node.cc
+++ b/libperfmgr/Node.cc
@@ -18,6 +18,8 @@
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <android-base/stringprintf.h>
 
 #include "perfmgr/Node.h"
 
@@ -146,5 +148,21 @@
     return values;
 }
 
+void Node::DumpToFd(int fd) {
+    std::string node_value;
+    if (!android::base::ReadFileToString(node_path_, &node_value)) {
+        LOG(ERROR) << "Failed to read node path: " << node_path_;
+    }
+    node_value = android::base::Trim(node_value);
+    std::string buf(android::base::StringPrintf("%s\t%s\t%zu\t%s\n",
+                                                name_.c_str(),
+                                                node_path_.c_str(),
+                                                current_val_index_,
+                                                node_value.c_str()));
+    if (!android::base::WriteStringToFd(buf, fd)) {
+        LOG(ERROR) << "Failed to dump fd: " << fd;
+    }
+}
+
 }  // namespace perfmgr
 }  // namespace android
diff --git a/libperfmgr/NodeLooperThread.cc b/libperfmgr/NodeLooperThread.cc
index cb2ea18..e7a63cc 100644
--- a/libperfmgr/NodeLooperThread.cc
+++ b/libperfmgr/NodeLooperThread.cc
@@ -88,6 +88,13 @@
     return ret;
 }
 
+void NodeLooperThread::DumpToFd(int fd) {
+    ::android::AutoMutex _l(lock_);
+    for (auto& n : nodes_) {
+        n->DumpToFd(fd);
+    }
+}
+
 bool NodeLooperThread::threadLoop() {
     ::android::AutoMutex _l(lock_);
     std::chrono::milliseconds timeout_ms = kMaxUpdatePeriod;
diff --git a/libperfmgr/OWNERS b/libperfmgr/OWNERS
new file mode 100644
index 0000000..03c33cd
--- /dev/null
+++ b/libperfmgr/OWNERS
@@ -0,0 +1 @@
+wvw@google.com
diff --git a/libperfmgr/include/perfmgr/HintManager.h b/libperfmgr/include/perfmgr/HintManager.h
index b21e31a..cff2ce9 100644
--- a/libperfmgr/include/perfmgr/HintManager.h
+++ b/libperfmgr/include/perfmgr/HintManager.h
@@ -64,6 +64,9 @@
     // Return available hints managed by HintManager
     std::vector<std::string> GetHints() const;
 
+    // Dump internal status to fd
+    void DumpToFd(int fd);
+
   protected:
     static std::vector<std::unique_ptr<Node>> ParseNodes(
         const std::string& json_doc);
diff --git a/libperfmgr/include/perfmgr/Node.h b/libperfmgr/include/perfmgr/Node.h
index 1bc46cb..f31b012 100644
--- a/libperfmgr/include/perfmgr/Node.h
+++ b/libperfmgr/include/perfmgr/Node.h
@@ -42,7 +42,8 @@
 // value. For each value, there may be multiple requests because different
 // powerhints may request the same value, and the requests may have different
 // expiration times. All of the in-progress powerhints for a given value are
-// collected in a RequestGroup.
+// collected in a RequestGroup. Node class is not thread safe so it need protection
+// from caller e.g. NodeLooperThread.
 class Node {
   public:
     Node(std::string name, std::string node_path,
@@ -69,6 +70,7 @@
     bool GetResetOnInit() const;
     bool GetHoldFd() const;
     bool GetValueIndex(const std::string value, std::size_t* index) const;
+    void DumpToFd(int fd);
 
   private:
     Node(const Node& other) = delete;
diff --git a/libperfmgr/include/perfmgr/NodeLooperThread.h b/libperfmgr/include/perfmgr/NodeLooperThread.h
index e8151c8..42267d4 100644
--- a/libperfmgr/include/perfmgr/NodeLooperThread.h
+++ b/libperfmgr/include/perfmgr/NodeLooperThread.h
@@ -71,6 +71,9 @@
     bool Cancel(const std::vector<NodeAction>& actions,
                 const std::string& hint_type);
 
+    // Dump all nodes to fd
+    void DumpToFd(int fd);
+
   private:
     NodeLooperThread(NodeLooperThread const&) = delete;
     void operator=(NodeLooperThread const&) = delete;
diff --git a/libperfmgr/tests/HintManagerTest.cc b/libperfmgr/tests/HintManagerTest.cc
index 16bb65f..0630fe7 100644
--- a/libperfmgr/tests/HintManagerTest.cc
+++ b/libperfmgr/tests/HintManagerTest.cc
@@ -150,7 +150,7 @@
     std::string json_doc_;
 };
 
-static inline void _VerifyPathValue(std::string path, std::string value) {
+static inline void _VerifyPathValue(const std::string& path, const std::string& value) {
     std::string s;
     EXPECT_TRUE(android::base::ReadFileToString(path, &s)) << strerror(errno);
     EXPECT_EQ(value, s);
diff --git a/libperfmgr/tests/NodeLooperThreadTest.cc b/libperfmgr/tests/NodeLooperThreadTest.cc
index 9d827e9..6f96cf8 100644
--- a/libperfmgr/tests/NodeLooperThreadTest.cc
+++ b/libperfmgr/tests/NodeLooperThreadTest.cc
@@ -54,7 +54,7 @@
     std::vector<std::unique_ptr<TemporaryFile>> files_;
 };
 
-static inline void _VerifyPathValue(std::string path, std::string value) {
+static inline void _VerifyPathValue(const std::string& path, const std::string& value) {
     std::string s;
     EXPECT_TRUE(android::base::ReadFileToString(path, &s)) << strerror(errno);
     EXPECT_EQ(value, s);
diff --git a/libperfmgr/tests/NodeTest.cc b/libperfmgr/tests/NodeTest.cc
index b1a384d..2e37a4d 100644
--- a/libperfmgr/tests/NodeTest.cc
+++ b/libperfmgr/tests/NodeTest.cc
@@ -18,6 +18,7 @@
 #include <thread>
 
 #include <android-base/file.h>
+#include <android-base/stringprintf.h>
 #include <android-base/test_utils.h>
 
 #include <gtest/gtest.h>
@@ -32,7 +33,7 @@
 constexpr double kTIMING_TOLERANCE_MS = std::chrono::milliseconds(25).count();
 constexpr auto kSLEEP_TOLERANCE_MS = 2ms;
 
-static inline void _VerifyPathValue(std::string path, std::string value) {
+static inline void _VerifyPathValue(const std::string& path, const std::string& value) {
     std::string s;
     EXPECT_TRUE(android::base::ReadFileToString(path, &s)) << strerror(errno);
     EXPECT_EQ(value, s);
@@ -55,6 +56,18 @@
     _VerifyPathValue(tf2.path, "value0");
 }
 
+// Test DumpToFd
+TEST(NodeTest, DumpToFdTest) {
+    TemporaryFile tf;
+    Node t("test_dump", tf.path, {{"value0"}, {"value1"}, {"value2"}}, 1, true);
+    TemporaryFile dumptf;
+    t.DumpToFd(dumptf.fd);
+    fsync(dumptf.fd);
+    std::string buf(android::base::StringPrintf("test_dump\t%s\t1\tvalue1\n",
+                                                tf.path));
+    _VerifyPathValue(dumptf.path, buf);
+}
+
 // Test GetValueIndex
 TEST(NodeTest, GetValueIndexTest) {
     TemporaryFile tf;