libperfmgr: Retry when writing to node failed

Test: libperfmgr_test

(cherry picked from commit 7ef92c9684700a19eef5f4e71d8261535bbdded8)

Change-Id: I6e957825d8ce77278eacbf489afd4d3721e5a986
diff --git a/libperfmgr/HintManager.cc b/libperfmgr/HintManager.cc
index 2444c7c..135e55a 100644
--- a/libperfmgr/HintManager.cc
+++ b/libperfmgr/HintManager.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "libperfmgr"
+
 #include <set>
 
 #include <android-base/file.h>
diff --git a/libperfmgr/Node.cc b/libperfmgr/Node.cc
index 9f275ec..6b24e9f 100644
--- a/libperfmgr/Node.cc
+++ b/libperfmgr/Node.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "libperfmgr"
+
 #include <android-base/file.h>
 #include <android-base/logging.h>
 
@@ -34,7 +36,7 @@
     if (reset_on_init) {
         // Assigning an invalid value so the next Update() will update the
         // Node's value to default
-        current_val_index_ = req_sorted.size();
+        current_val_index_ = req_sorted_.size();
         Update();
     } else {
         current_val_index_ = default_val_index;
@@ -76,16 +78,16 @@
 
     // Update node only if request index changes
     if (value_index != current_val_index_) {
-        current_val_index_ = value_index;
-        std::string req_value =
-            req_sorted_[current_val_index_].GetRequestValue();
+        std::string req_value = req_sorted_[value_index].GetRequestValue();
 
         fd_.reset(TEMP_FAILURE_RETRY(
             open(node_path_.c_str(), O_WRONLY | O_CLOEXEC | O_TRUNC)));
 
         if (fd_ == -1 || !android::base::WriteStringToFd(req_value, fd_)) {
             LOG(ERROR) << "Failed to write to node: " << node_path_
-                       << " with value: " << req_value;
+                       << " with value: " << req_value << ", fd: " << fd_;
+            // Retry in 500ms or sooner
+            expire_time = std::min(expire_time, std::chrono::milliseconds(500));
         } else {
             // For regular file system, we need fsync
             fsync(fd_);
@@ -97,6 +99,8 @@
             if ((!hold_fd_) || value_index == default_val_index_) {
                 fd_.reset();
             }
+            // Update current index only when succeed
+            current_val_index_ = value_index;
         }
     }
     return expire_time;
diff --git a/libperfmgr/NodeLooperThread.cc b/libperfmgr/NodeLooperThread.cc
index 5c7ba5a..da7aa65 100644
--- a/libperfmgr/NodeLooperThread.cc
+++ b/libperfmgr/NodeLooperThread.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "libperfmgr"
+
 #include <android-base/file.h>
 #include <android-base/logging.h>
 
diff --git a/libperfmgr/RequestGroup.cc b/libperfmgr/RequestGroup.cc
index f2cb7aa..1c7a96a 100644
--- a/libperfmgr/RequestGroup.cc
+++ b/libperfmgr/RequestGroup.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "libperfmgr"
+
 #include "perfmgr/RequestGroup.h"
 
 namespace android {
diff --git a/libperfmgr/tests/NodeTest.cc b/libperfmgr/tests/NodeTest.cc
index c5b97a1..b1a384d 100644
--- a/libperfmgr/tests/NodeTest.cc
+++ b/libperfmgr/tests/NodeTest.cc
@@ -50,6 +50,9 @@
     TemporaryFile tf;
     Node t("t", tf.path, {{"value0"}, {"value1"}, {"value2"}}, 1, true);
     _VerifyPathValue(tf.path, "value1");
+    TemporaryFile tf2;
+    Node t2("t2", tf2.path, {{"value0"}, {"value1"}, {"value2"}}, 0, true);
+    _VerifyPathValue(tf2.path, "value0");
 }
 
 // Test GetValueIndex
@@ -88,6 +91,24 @@
     EXPECT_TRUE(t.GetHoldFd());
 }
 
+// Test add request fail and retry
+TEST(NodeTest, AddRequestTestFail) {
+    Node t("t", "/sys/android/nonexist_node_test",
+           {{"value0"}, {"value1"}, {"value2"}}, 2, true);
+    auto start = std::chrono::steady_clock::now();
+    EXPECT_TRUE(t.AddRequest(1, "INTERACTION", start + 200ms));
+    std::chrono::milliseconds expire_time = t.Update();
+    // Add request @ value1
+    EXPECT_NEAR(std::chrono::milliseconds(200).count(), expire_time.count(),
+                kTIMING_TOLERANCE_MS);
+    // Add request @ value0 higher prio than value1
+    EXPECT_TRUE(t.AddRequest(0, "LAUNCH", start + 2000ms));
+    expire_time = t.Update();
+    // Retry in 500 ms
+    EXPECT_NEAR(std::chrono::milliseconds(500).count(), expire_time.count(),
+                kTIMING_TOLERANCE_MS);
+}
+
 // Test add request
 TEST(NodeTest, AddRequestTest) {
     TemporaryFile tf;