Add unit test for AidlPowerHalWrapper

Bug: b/195990840
Test: atest libsurfaceflinger_unittest:libsurfaceflinger_unittest.AidlPowerHalWrapperTest
Change-Id: I5b2197904445a83e5d586aa6331ccc3d46db22a3
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 44c086d..05f488b 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -32,7 +32,6 @@
 #include <utils/Trace.h>
 
 #include <android/hardware/power/1.3/IPower.h>
-#include <android/hardware/power/IPower.h>
 #include <android/hardware/power/IPowerHintSession.h>
 #include <android/hardware/power/WorkDuration.h>
 
@@ -62,8 +61,6 @@
 
 using scheduler::OneShotTimer;
 
-class AidlPowerHalWrapper;
-
 PowerAdvisor::~PowerAdvisor() = default;
 
 namespace {
@@ -294,259 +291,232 @@
     const sp<V1_3::IPower> mPowerHal = nullptr;
 };
 
-class AidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
-public:
-    AidlPowerHalWrapper(sp<IPower> powerHal) : mPowerHal(std::move(powerHal)) {
-        auto ret = mPowerHal->isModeSupported(Mode::EXPENSIVE_RENDERING, &mHasExpensiveRendering);
-        if (!ret.isOk()) {
-            mHasExpensiveRendering = false;
-        }
-
-        ret = mPowerHal->isBoostSupported(Boost::DISPLAY_UPDATE_IMMINENT,
-                                          &mHasDisplayUpdateImminent);
-        if (!ret.isOk()) {
-            mHasDisplayUpdateImminent = false;
-        }
-
-        mSupportsPowerHint = checkPowerHintSessionSupported();
+AidlPowerHalWrapper::AidlPowerHalWrapper(sp<IPower> powerHal) : mPowerHal(std::move(powerHal)) {
+    auto ret = mPowerHal->isModeSupported(Mode::EXPENSIVE_RENDERING, &mHasExpensiveRendering);
+    if (!ret.isOk()) {
+        mHasExpensiveRendering = false;
     }
 
-    ~AidlPowerHalWrapper() override {
-        if (mPowerHintSession != nullptr) {
-            mPowerHintSession->close();
-            mPowerHintSession = nullptr;
-        }
-    };
-
-    static std::unique_ptr<HalWrapper> connect() {
-        // This only waits if the service is actually declared
-        sp<IPower> powerHal = waitForVintfService<IPower>();
-        if (powerHal == nullptr) {
-            return nullptr;
-        }
-        ALOGI("Loaded AIDL Power HAL service");
-
-        return std::make_unique<AidlPowerHalWrapper>(std::move(powerHal));
+    ret = mPowerHal->isBoostSupported(Boost::DISPLAY_UPDATE_IMMINENT, &mHasDisplayUpdateImminent);
+    if (!ret.isOk()) {
+        mHasDisplayUpdateImminent = false;
     }
 
-    bool setExpensiveRendering(bool enabled) override {
-        ALOGV("AIDL setExpensiveRendering %s", enabled ? "T" : "F");
-        if (!mHasExpensiveRendering) {
-            ALOGV("Skipped sending EXPENSIVE_RENDERING because HAL doesn't support it");
-            return true;
-        }
+    mSupportsPowerHint = checkPowerHintSessionSupported();
+}
 
-        auto ret = mPowerHal->setMode(Mode::EXPENSIVE_RENDERING, enabled);
-        if (ret.isOk()) {
-            traceExpensiveRendering(enabled);
-        }
-        return ret.isOk();
+AidlPowerHalWrapper::~AidlPowerHalWrapper() {
+    if (mPowerHintSession != nullptr) {
+        mPowerHintSession->close();
+        mPowerHintSession = nullptr;
     }
-
-    bool notifyDisplayUpdateImminent() override {
-        ALOGV("AIDL notifyDisplayUpdateImminent");
-        if (!mHasDisplayUpdateImminent) {
-            ALOGV("Skipped sending DISPLAY_UPDATE_IMMINENT because HAL doesn't support it");
-            return true;
-        }
-
-        auto ret = mPowerHal->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 0);
-        return ret.isOk();
-    }
-
-    // only version 2+ of the aidl supports power hint sessions, hidl has no support
-    bool supportsPowerHintSession() override { return mSupportsPowerHint; }
-
-    bool checkPowerHintSessionSupported() {
-        int64_t unused;
-        // Try to get preferred rate to determine if hint sessions are supported
-        // We check for isOk not EX_UNSUPPORTED_OPERATION to lump other errors
-        return mPowerHal->getHintSessionPreferredRate(&unused).isOk();
-    }
-
-    bool isPowerHintSessionRunning() override { return mPowerHintSession != nullptr; }
-
-    void closePowerHintSession() {
-        if (mPowerHintSession != nullptr) {
-            mPowerHintSession->close();
-            mPowerHintSession = nullptr;
-        }
-    }
-
-    void restartPowerHintSession() {
-        closePowerHintSession();
-        startPowerHintSession();
-    }
-
-    void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) override {
-        if (threadIds != mPowerHintThreadIds) {
-            mPowerHintThreadIds = threadIds;
-            if (isPowerHintSessionRunning()) {
-                restartPowerHintSession();
-            }
-        }
-    }
-
-    bool startPowerHintSession() override {
-        if (mPowerHintSession != nullptr || mPowerHintThreadIds.empty()) {
-            ALOGV("Cannot start power hint session, skipping");
-            return false;
-        }
-        auto ret = mPowerHal->createHintSession(getpid(), static_cast<int32_t>(getuid()),
-                                                mPowerHintThreadIds, mTargetDuration,
-                                                &mPowerHintSession);
-        if (!ret.isOk()) {
-            ALOGW("Failed to start power hint session with error: %s",
-                  ret.exceptionToString(ret.exceptionCode()).c_str());
-        } else {
-            mLastTargetDurationSent = mTargetDuration;
-        }
-        return isPowerHintSessionRunning();
-    }
-
-    bool shouldSetTargetDuration(int64_t targetDurationNanos) {
-        // report if the change in target from our last submission to now exceeds the threshold
-        return abs(1.0 -
-                   static_cast<double>(mLastTargetDurationSent) /
-                           static_cast<double>(targetDurationNanos)) >=
-                kAllowedTargetDeviationPercent;
-    }
-
-    void setTargetWorkDuration(int64_t targetDurationNanos) override {
-        ATRACE_CALL();
-        mTargetDuration = targetDurationNanos;
-        if (sTraceHintSessionData) ATRACE_INT64("Time target", targetDurationNanos);
-        if (!sNormalizeTarget && shouldSetTargetDuration(targetDurationNanos) &&
-            isPowerHintSessionRunning()) {
-            if (mLastActualDurationSent.has_value()) {
-                // update the error term here since we are actually sending an update to powerhal
-                if (sTraceHintSessionData)
-                    ATRACE_INT64("Target error term",
-                                 targetDurationNanos - *mLastActualDurationSent);
-            }
-            ALOGV("Sending target time: %lld ns", static_cast<long long>(targetDurationNanos));
-            mLastTargetDurationSent = targetDurationNanos;
-            auto ret = mPowerHintSession->updateTargetWorkDuration(targetDurationNanos);
-            if (!ret.isOk()) {
-                ALOGW("Failed to set power hint target work duration with error: %s",
-                      ret.exceptionMessage().c_str());
-                mShouldReconnectHal = true;
-            }
-        }
-    }
-
-    bool shouldReportActualDurationsNow() {
-        // report if we have never reported before or are approaching a stale session
-        if (!mLastActualDurationSent.has_value() ||
-            (systemTime() - mLastActualReportTimestamp) > kStaleTimeout.count()) {
-            return true;
-        }
-
-        if (!mActualDuration.has_value()) {
-            return false;
-        }
-
-        // duration of most recent timing
-        const double mostRecentActualDuration = static_cast<double>(*mActualDuration);
-        // duration of the last timing actually reported to the powerhal
-        const double lastReportedActualDuration = static_cast<double>(*mLastActualDurationSent);
-
-        // report if the change in duration from then to now exceeds the threshold
-        return abs(1.0 - mostRecentActualDuration / lastReportedActualDuration) >=
-                kAllowedActualDeviationPercent;
-    }
-
-    void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timeStampNanos) override {
-        ATRACE_CALL();
-
-        if (actualDurationNanos < 0 || !isPowerHintSessionRunning()) {
-            ALOGV("Failed to send actual work duration, skipping");
-            return;
-        }
-
-        WorkDuration duration;
-        duration.durationNanos = actualDurationNanos;
-        mActualDuration = actualDurationNanos;
-
-        // normalize the sent values to a pre-set target
-        if (sNormalizeTarget) {
-            duration.durationNanos += mLastTargetDurationSent - mTargetDuration;
-        }
-        duration.timeStampNanos = timeStampNanos;
-        mPowerHintQueue.push_back(duration);
-
-        long long targetNsec = mTargetDuration;
-        long long durationNsec = actualDurationNanos;
-
-        if (sTraceHintSessionData) {
-            ATRACE_INT64("Measured duration", durationNsec);
-            ATRACE_INT64("Target error term", targetNsec - durationNsec);
-        }
-
-        ALOGV("Sending actual work duration of: %lld on target: %lld with error: %lld",
-              durationNsec, targetNsec, targetNsec - durationNsec);
-
-        // This rate limiter queues similar duration reports to the powerhal into
-        // batches to avoid excessive binder calls. The criteria to send a given batch
-        // are outlined in shouldReportActualDurationsNow()
-        if (shouldReportActualDurationsNow()) {
-            ALOGV("Sending hint update batch");
-            mLastActualReportTimestamp = systemTime();
-            auto ret = mPowerHintSession->reportActualWorkDuration(mPowerHintQueue);
-            if (!ret.isOk()) {
-                ALOGW("Failed to report actual work durations with error: %s",
-                      ret.exceptionMessage().c_str());
-                mShouldReconnectHal = true;
-            }
-            mPowerHintQueue.clear();
-            // we save the non-normalized value here to detect % changes
-            mLastActualDurationSent = actualDurationNanos;
-        }
-    }
-
-    bool shouldReconnectHAL() override { return mShouldReconnectHal; }
-
-    std::vector<int32_t> getPowerHintSessionThreadIds() override { return mPowerHintThreadIds; }
-
-    std::optional<int64_t> getTargetWorkDuration() override { return mTargetDuration; }
-
-private:
-    const sp<IPower> mPowerHal = nullptr;
-    bool mHasExpensiveRendering = false;
-    bool mHasDisplayUpdateImminent = false;
-    // Used to indicate an error state and need for reconstruction
-    bool mShouldReconnectHal = false;
-    // This is not thread safe, but is currently protected by mPowerHalMutex so it needs no lock
-    sp<IPowerHintSession> mPowerHintSession = nullptr;
-    // Queue of actual durations saved to report
-    std::vector<WorkDuration> mPowerHintQueue;
-    // The latest un-normalized values we have received for target and actual
-    int64_t mTargetDuration = kDefaultTarget.count();
-    std::optional<int64_t> mActualDuration;
-    // The list of thread ids, stored so we can restart the session from this class if needed
-    std::vector<int32_t> mPowerHintThreadIds;
-    bool mSupportsPowerHint;
-    // Keep track of the last messages sent for rate limiter change detection
-    std::optional<int64_t> mLastActualDurationSent;
-    // timestamp of the last report we sent, used to avoid stale sessions
-    int64_t mLastActualReportTimestamp = 0;
-    int64_t mLastTargetDurationSent = kDefaultTarget.count();
-    // Whether to normalize all the actual values as error terms relative to a constant target
-    // This saves a binder call by not setting the target, and should not affect the pid values
-    static const bool sNormalizeTarget;
-    // Whether we should emit ATRACE_INT data for hint sessions
-    static const bool sTraceHintSessionData;
-    // 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;
-    // 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
-    // actually 100ms but we use 80 here to ideally avoid going stale
-    static constexpr const std::chrono::nanoseconds kStaleTimeout = 80ms;
 };
 
+std::unique_ptr<PowerAdvisor::HalWrapper> AidlPowerHalWrapper::connect() {
+    // This only waits if the service is actually declared
+    sp<IPower> powerHal = waitForVintfService<IPower>();
+    if (powerHal == nullptr) {
+        return nullptr;
+    }
+    ALOGI("Loaded AIDL Power HAL service");
+
+    return std::make_unique<AidlPowerHalWrapper>(std::move(powerHal));
+}
+
+bool AidlPowerHalWrapper::setExpensiveRendering(bool enabled) {
+    ALOGV("AIDL setExpensiveRendering %s", enabled ? "T" : "F");
+    if (!mHasExpensiveRendering) {
+        ALOGV("Skipped sending EXPENSIVE_RENDERING because HAL doesn't support it");
+        return true;
+    }
+
+    auto ret = mPowerHal->setMode(Mode::EXPENSIVE_RENDERING, enabled);
+    if (ret.isOk()) {
+        traceExpensiveRendering(enabled);
+    }
+    return ret.isOk();
+}
+
+bool AidlPowerHalWrapper::notifyDisplayUpdateImminent() {
+    ALOGV("AIDL notifyDisplayUpdateImminent");
+    if (!mHasDisplayUpdateImminent) {
+        ALOGV("Skipped sending DISPLAY_UPDATE_IMMINENT because HAL doesn't support it");
+        return true;
+    }
+
+    auto ret = mPowerHal->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 0);
+    return ret.isOk();
+}
+
+// only version 2+ of the aidl supports power hint sessions, hidl has no support
+bool AidlPowerHalWrapper::supportsPowerHintSession() {
+    return mSupportsPowerHint;
+}
+
+bool AidlPowerHalWrapper::checkPowerHintSessionSupported() {
+    int64_t unused;
+    // Try to get preferred rate to determine if hint sessions are supported
+    // We check for isOk not EX_UNSUPPORTED_OPERATION to lump together errors
+    return mPowerHal->getHintSessionPreferredRate(&unused).isOk();
+}
+
+bool AidlPowerHalWrapper::isPowerHintSessionRunning() {
+    return mPowerHintSession != nullptr;
+}
+
+void AidlPowerHalWrapper::closePowerHintSession() {
+    if (mPowerHintSession != nullptr) {
+        mPowerHintSession->close();
+        mPowerHintSession = nullptr;
+    }
+}
+
+void AidlPowerHalWrapper::restartPowerHintSession() {
+    closePowerHintSession();
+    startPowerHintSession();
+}
+
+void AidlPowerHalWrapper::setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) {
+    if (threadIds != mPowerHintThreadIds) {
+        mPowerHintThreadIds = threadIds;
+        if (isPowerHintSessionRunning()) {
+            restartPowerHintSession();
+        }
+    }
+}
+
+bool AidlPowerHalWrapper::startPowerHintSession() {
+    if (mPowerHintSession != nullptr || mPowerHintThreadIds.empty()) {
+        ALOGV("Cannot start power hint session, skipping");
+        return false;
+    }
+    auto ret =
+            mPowerHal->createHintSession(getpid(), static_cast<int32_t>(getuid()),
+                                         mPowerHintThreadIds, mTargetDuration, &mPowerHintSession);
+    if (!ret.isOk()) {
+        ALOGW("Failed to start power hint session with error: %s",
+              ret.exceptionToString(ret.exceptionCode()).c_str());
+    } else {
+        mLastTargetDurationSent = mTargetDuration;
+    }
+    return isPowerHintSessionRunning();
+}
+
+bool AidlPowerHalWrapper::shouldSetTargetDuration(int64_t targetDurationNanos) {
+    if (targetDurationNanos <= 0) {
+        return false;
+    }
+    // report if the change in target from our last submission to now exceeds the threshold
+    return abs(1.0 -
+               static_cast<double>(mLastTargetDurationSent) /
+                       static_cast<double>(targetDurationNanos)) >= kAllowedTargetDeviationPercent;
+}
+
+void AidlPowerHalWrapper::setTargetWorkDuration(int64_t targetDurationNanos) {
+    ATRACE_CALL();
+    mTargetDuration = targetDurationNanos;
+    if (sTraceHintSessionData) ATRACE_INT64("Time target", targetDurationNanos);
+    if (!sNormalizeTarget && isPowerHintSessionRunning() &&
+        shouldSetTargetDuration(targetDurationNanos)) {
+        if (mLastActualDurationSent.has_value()) {
+            // update the error term here since we are actually sending an update to powerhal
+            if (sTraceHintSessionData)
+                ATRACE_INT64("Target error term", targetDurationNanos - *mLastActualDurationSent);
+        }
+        ALOGV("Sending target time: %" PRId64 "ns", targetDurationNanos);
+        mLastTargetDurationSent = targetDurationNanos;
+        auto ret = mPowerHintSession->updateTargetWorkDuration(targetDurationNanos);
+        if (!ret.isOk()) {
+            ALOGW("Failed to set power hint target work duration with error: %s",
+                  ret.exceptionMessage().c_str());
+            mShouldReconnectHal = true;
+        }
+    }
+}
+
+bool AidlPowerHalWrapper::shouldReportActualDurationsNow() {
+    // report if we have never reported before or are approaching a stale session
+    if (!mLastActualDurationSent.has_value() ||
+        (systemTime() - mLastActualReportTimestamp) > kStaleTimeout.count()) {
+        return true;
+    }
+
+    if (!mActualDuration.has_value()) {
+        return false;
+    }
+
+    // duration of most recent timing
+    const double mostRecentActualDuration = static_cast<double>(*mActualDuration);
+    // duration of the last timing actually reported to the powerhal
+    const double lastReportedActualDuration = static_cast<double>(*mLastActualDurationSent);
+
+    // report if the change in duration from then to now exceeds the threshold
+    return abs(1.0 - mostRecentActualDuration / lastReportedActualDuration) >=
+            kAllowedActualDeviationPercent;
+}
+
+void AidlPowerHalWrapper::sendActualWorkDuration(int64_t actualDurationNanos,
+                                                 nsecs_t timeStampNanos) {
+    ATRACE_CALL();
+
+    if (actualDurationNanos < 0 || !isPowerHintSessionRunning()) {
+        ALOGV("Failed to send actual work duration, skipping");
+        return;
+    }
+
+    WorkDuration duration;
+    duration.durationNanos = actualDurationNanos;
+    mActualDuration = actualDurationNanos;
+
+    // normalize the sent values to a pre-set target
+    if (sNormalizeTarget) {
+        duration.durationNanos += mLastTargetDurationSent - mTargetDuration;
+    }
+    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);
+    }
+
+    ALOGV("Sending actual work duration of: %" PRId64 " on target: %" PRId64
+          " with error: %" PRId64,
+          durationNsec, targetNsec, targetNsec - durationNsec);
+
+    // This rate limiter queues similar duration reports to the powerhal into
+    // batches to avoid excessive binder calls. The criteria to send a given batch
+    // are outlined in shouldReportActualDurationsNow()
+    if (shouldReportActualDurationsNow()) {
+        ALOGV("Sending hint update batch");
+        mLastActualReportTimestamp = systemTime();
+        auto ret = mPowerHintSession->reportActualWorkDuration(mPowerHintQueue);
+        if (!ret.isOk()) {
+            ALOGW("Failed to report actual work durations with error: %s",
+                  ret.exceptionMessage().c_str());
+            mShouldReconnectHal = true;
+        }
+        mPowerHintQueue.clear();
+        // we save the non-normalized value here to detect % changes
+        mLastActualDurationSent = actualDurationNanos;
+    }
+}
+
+bool AidlPowerHalWrapper::shouldReconnectHAL() {
+    return mShouldReconnectHal;
+}
+
+std::vector<int32_t> AidlPowerHalWrapper::getPowerHintSessionThreadIds() {
+    return mPowerHintThreadIds;
+}
+
+std::optional<int64_t> AidlPowerHalWrapper::getTargetWorkDuration() {
+    return mTargetDuration;
+}
+
 const bool AidlPowerHalWrapper::sTraceHintSessionData =
         base::GetBoolProperty(std::string("debug.sf.trace_hint_sessions"), false);