Adjust actual work duration when target time is changed within allowed deviation limit

Bump the target time deviation limit to 10%

Bug: 195990840
Test: Test: atest libsurfaceflinger_unittest:libsurfaceflinger_unittest.AidlPowerHalWrapperTest
Change-Id: Ifccdb377dce90ef0efa4b2d71c54841f31989182
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 05f488b..cbafdd3 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -463,29 +463,41 @@
         ALOGV("Failed to send actual work duration, skipping");
         return;
     }
-
-    WorkDuration duration;
-    duration.durationNanos = actualDurationNanos;
-    mActualDuration = actualDurationNanos;
+    nsecs_t reportedDuration = actualDurationNanos;
 
     // normalize the sent values to a pre-set target
     if (sNormalizeTarget) {
-        duration.durationNanos += mLastTargetDurationSent - mTargetDuration;
+        reportedDuration += mLastTargetDurationSent - mTargetDuration;
+    } else {
+        // when target duration change is within deviation and not updated, adjust the actual
+        // duration proportionally based on the difference, e.g. if new target is 5ms longer than
+        // last reported but actual duration is the same as last target, we want to report a smaller
+        // actual work duration now to indicate that we are overshooting
+        if (mLastTargetDurationSent != kDefaultTarget.count() && mTargetDuration != 0) {
+            reportedDuration =
+                    static_cast<int64_t>(static_cast<long double>(mLastTargetDurationSent) /
+                                         mTargetDuration * actualDurationNanos);
+            mActualDuration = reportedDuration;
+        }
     }
+    mActualDuration = reportedDuration;
+    WorkDuration duration;
+    duration.durationNanos = reportedDuration;
     duration.timeStampNanos = timeStampNanos;
     mPowerHintQueue.push_back(duration);
 
-    nsecs_t targetNsec = mTargetDuration;
-    nsecs_t durationNsec = actualDurationNanos;
-
     if (sTraceHintSessionData) {
-        ATRACE_INT64("Measured duration", durationNsec);
-        ATRACE_INT64("Target error term", targetNsec - durationNsec);
+        ATRACE_INT64("Measured duration", actualDurationNanos);
+        ATRACE_INT64("Target error term", mTargetDuration - actualDurationNanos);
+
+        ATRACE_INT64("Reported duration", reportedDuration);
+        ATRACE_INT64("Reported target", mLastTargetDurationSent);
+        ATRACE_INT64("Reported target error term", mLastTargetDurationSent - reportedDuration);
     }
 
-    ALOGV("Sending actual work duration of: %" PRId64 " on target: %" PRId64
+    ALOGV("Sending actual work duration of: %" PRId64 " on reported target: %" PRId64
           " with error: %" PRId64,
-          durationNsec, targetNsec, targetNsec - durationNsec);
+          reportedDuration, mLastTargetDurationSent, mLastTargetDurationSent - reportedDuration);
 
     // This rate limiter queues similar duration reports to the powerhal into
     // batches to avoid excessive binder calls. The criteria to send a given batch
@@ -501,7 +513,7 @@
         }
         mPowerHintQueue.clear();
         // we save the non-normalized value here to detect % changes
-        mLastActualDurationSent = actualDurationNanos;
+        mLastActualDurationSent = reportedDuration;
     }
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
index 3f47ffd..61bb32b 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -173,8 +173,8 @@
 
     // Max percent the actual duration can vary without causing a report (eg: 0.1 = 10%)
     static constexpr double kAllowedActualDeviationPercent = 0.1;
-    // Max percent the target duration can vary without causing a report (eg: 0.05 = 5%)
-    static constexpr double kAllowedTargetDeviationPercent = 0.05;
+    // Max percent the target duration can vary without causing a report (eg: 0.1 = 10%)
+    static constexpr double kAllowedTargetDeviationPercent = 0.1;
     // Target used for init and normalization, the actual value does not really matter
     static constexpr const std::chrono::nanoseconds kDefaultTarget = 50ms;
     // Amount of time after the last message was sent before the session goes stale
diff --git a/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp b/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp
index e25a0ae..9ab35d7 100644
--- a/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp
+++ b/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp
@@ -17,6 +17,7 @@
 #undef LOG_TAG
 #define LOG_TAG "AidlPowerHalWrapperTest"
 
+#include <android-base/stringprintf.h>
 #include <android/hardware/power/IPower.h>
 #include <android/hardware/power/IPowerHintSession.h>
 #include <gmock/gmock.h>
@@ -82,6 +83,15 @@
     return duration;
 }
 
+std::string printWorkDurations(const ::std::vector<WorkDuration>& durations) {
+    std::ostringstream os;
+    for (auto duration : durations) {
+        os << duration.toString();
+        os << "\n";
+    }
+    return os.str();
+}
+
 namespace {
 TEST_F(AidlPowerHalWrapperTest, supportsPowerHintSession) {
     ASSERT_TRUE(mWrapper->supportsPowerHintSession());
@@ -143,8 +153,8 @@
                                                                               {-1ms, false},
                                                                               {200ms, true},
                                                                               {2ms, true},
-                                                                              {96ms, false},
-                                                                              {104ms, false}};
+                                                                              {91ms, false},
+                                                                              {109ms, false}};
 
     for (const auto& test : testCases) {
         // reset to 100ms baseline
@@ -212,6 +222,40 @@
     }
 }
 
+TEST_F(AidlPowerHalWrapperTest, sendAdjustedActualWorkDuration) {
+    ASSERT_TRUE(mWrapper->supportsPowerHintSession());
+
+    std::vector<int32_t> threadIds = {1, 2};
+    mWrapper->setPowerHintSessionThreadIds(threadIds);
+    EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
+            .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
+    ASSERT_TRUE(mWrapper->startPowerHintSession());
+    verifyAndClearExpectations();
+
+    std::chrono::nanoseconds lastTarget = 100ms;
+    EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(lastTarget.count())).Times(1);
+    mWrapper->setTargetWorkDuration(lastTarget.count());
+    std::chrono::nanoseconds newTarget = 105ms;
+    mWrapper->setTargetWorkDuration(newTarget.count());
+    EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(newTarget.count())).Times(0);
+    std::chrono::nanoseconds actual = 21ms;
+    // 100 / 105 * 21ms = 20ms
+    std::chrono::nanoseconds expectedActualSent = 20ms;
+    std::vector<WorkDuration> expectedDurations = {toWorkDuration(expectedActualSent, 1)};
+
+    EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(_))
+            .WillOnce(DoAll(
+                    [expectedDurations](const ::std::vector<WorkDuration>& durationsSent) {
+                        EXPECT_EQ(expectedDurations, durationsSent)
+                                << base::StringPrintf("actual sent: %s vs expected: %s",
+                                                      printWorkDurations(durationsSent).c_str(),
+                                                      printWorkDurations(expectedDurations)
+                                                              .c_str());
+                    },
+                    Return(Status::ok())));
+    mWrapper->sendActualWorkDuration(actual.count(), 1);
+}
+
 TEST_F(AidlPowerHalWrapperTest, sendActualWorkDuration_exceedsStaleTime) {
     ASSERT_TRUE(mWrapper->supportsPowerHintSession());