Rewrite the PowerAdvisor using standard power wrappers and clean up

* Replace custom AIDL/HIDL wrappers with libpowermanager
* Remove early hint code as it is deprecated for load change hints

Bug: b/245975645
Bug: b/244358432
Test: atest libsurfaceflinger_unittest

Change-Id: I2a11779ce1f78bcf29ea0e7978cb8933e74e9f7b
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 36f71bb..37b68c8 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -31,7 +31,7 @@
 #include <utils/Mutex.h>
 #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>
 
@@ -49,12 +49,7 @@
 
 namespace impl {
 
-namespace V1_0 = android::hardware::power::V1_0;
-namespace V1_3 = android::hardware::power::V1_3;
-using V1_3::PowerHint;
-
 using android::hardware::power::Boost;
-using android::hardware::power::IPower;
 using android::hardware::power::IPowerHintSession;
 using android::hardware::power::Mode;
 using android::hardware::power::SessionHint;
@@ -80,7 +75,8 @@
 
 } // namespace
 
-PowerAdvisor::PowerAdvisor(SurfaceFlinger& flinger) : mFlinger(flinger) {
+PowerAdvisor::PowerAdvisor(SurfaceFlinger& flinger)
+      : mPowerHal(std::make_unique<power::PowerHalController>()), mFlinger(flinger) {
     if (getUpdateTimeout() > 0ms) {
         mScreenUpdateTimer.emplace("UpdateImminentTimer", getUpdateTimeout(),
                                    /* resetCallback */ nullptr,
@@ -117,6 +113,10 @@
 }
 
 void PowerAdvisor::setExpensiveRenderingExpected(DisplayId displayId, bool expected) {
+    if (!mHasExpensiveRendering) {
+        ALOGV("Skipped sending EXPENSIVE_RENDERING because HAL doesn't support it");
+        return;
+    }
     if (expected) {
         mExpensiveDisplays.insert(displayId);
     } else {
@@ -125,19 +125,16 @@
 
     const bool expectsExpensiveRendering = !mExpensiveDisplays.empty();
     if (mNotifiedExpensiveRendering != expectsExpensiveRendering) {
-        std::lock_guard lock(mPowerHalMutex);
-        HalWrapper* const halWrapper = getPowerHal();
-        if (halWrapper == nullptr) {
-            return;
-        }
-
-        if (!halWrapper->setExpensiveRendering(expectsExpensiveRendering)) {
-            // The HAL has become unavailable; attempt to reconnect later
-            mReconnectPowerHal = true;
+        auto ret = getPowerHal().setMode(Mode::EXPENSIVE_RENDERING, expectsExpensiveRendering);
+        if (!ret.isOk()) {
+            if (ret.isUnsupported()) {
+                mHasExpensiveRendering = false;
+            }
             return;
         }
 
         mNotifiedExpensiveRendering = expectsExpensiveRendering;
+        traceExpensiveRendering(mNotifiedExpensiveRendering);
     }
 }
 
@@ -149,16 +146,22 @@
     }
 
     if (mSendUpdateImminent.exchange(false)) {
-        std::lock_guard lock(mPowerHalMutex);
-        HalWrapper* const halWrapper = getPowerHal();
-        if (halWrapper == nullptr) {
-            return;
+        ALOGV("AIDL notifyDisplayUpdateImminentAndCpuReset");
+        if (usePowerHintSession() && ensurePowerHintSessionRunning()) {
+            std::lock_guard lock(mHintSessionMutex);
+            auto ret = mHintSession->sendHint(SessionHint::CPU_LOAD_RESET);
+            if (!ret.isOk()) {
+                mHintSessionRunning = false;
+            }
         }
 
-        if (!halWrapper->notifyDisplayUpdateImminentAndCpuReset()) {
-            // The HAL has become unavailable; attempt to reconnect later
-            mReconnectPowerHal = true;
-            return;
+        if (!mHasDisplayUpdateImminent) {
+            ALOGV("Skipped sending DISPLAY_UPDATE_IMMINENT because HAL doesn't support it");
+        } else {
+            auto ret = getPowerHal().setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 0);
+            if (ret.isUnsupported()) {
+                mHasDisplayUpdateImminent = false;
+            }
         }
 
         if (mScreenUpdateTimer) {
@@ -178,87 +181,123 @@
 // checks both if it supports and if it's enabled
 bool PowerAdvisor::usePowerHintSession() {
     // uses cached value since the underlying support and flag are unlikely to change at runtime
-    return mPowerHintEnabled.value_or(false) && supportsPowerHintSession();
+    return mHintSessionEnabled.value_or(false) && supportsPowerHintSession();
 }
 
 bool PowerAdvisor::supportsPowerHintSession() {
     // cache to avoid needing lock every time
-    if (!mSupportsPowerHint.has_value()) {
-        std::lock_guard lock(mPowerHalMutex);
-        HalWrapper* const halWrapper = getPowerHal();
-        mSupportsPowerHint = halWrapper && halWrapper->supportsPowerHintSession();
+    if (!mSupportsHintSession.has_value()) {
+        mSupportsHintSession = getPowerHal().getHintSessionPreferredRate().isOk();
     }
-    return *mSupportsPowerHint;
+    return *mSupportsHintSession;
 }
 
-bool PowerAdvisor::isPowerHintSessionRunning() {
-    return mPowerHintSessionRunning;
+bool PowerAdvisor::ensurePowerHintSessionRunning() {
+    if (!mHintSessionRunning && !mHintSessionThreadIds.empty() && usePowerHintSession()) {
+        startPowerHintSession(mHintSessionThreadIds);
+    }
+    return mHintSessionRunning;
 }
 
-void PowerAdvisor::setTargetWorkDuration(Duration targetDuration) {
+void PowerAdvisor::updateTargetWorkDuration(Duration targetDuration) {
     if (!usePowerHintSession()) {
         ALOGV("Power hint session target duration cannot be set, skipping");
         return;
     }
+    ATRACE_CALL();
     {
-        std::lock_guard lock(mPowerHalMutex);
-        HalWrapper* const halWrapper = getPowerHal();
-        if (halWrapper != nullptr) {
-            halWrapper->setTargetWorkDuration(targetDuration);
+        mTargetDuration = targetDuration;
+        if (sTraceHintSessionData) ATRACE_INT64("Time target", targetDuration.ns());
+        if (ensurePowerHintSessionRunning() && (targetDuration != mLastTargetDurationSent)) {
+            ALOGV("Sending target time: %" PRId64 "ns", targetDuration.ns());
+            mLastTargetDurationSent = targetDuration;
+            std::lock_guard lock(mHintSessionMutex);
+            auto ret = mHintSession->updateTargetWorkDuration(targetDuration.ns());
+            if (!ret.isOk()) {
+                ALOGW("Failed to set power hint target work duration with error: %s",
+                      ret.exceptionMessage().c_str());
+                mHintSessionRunning = false;
+            }
         }
     }
 }
 
-void PowerAdvisor::sendActualWorkDuration() {
+void PowerAdvisor::reportActualWorkDuration() {
     if (!mBootFinished || !usePowerHintSession()) {
         ALOGV("Actual work duration power hint cannot be sent, skipping");
         return;
     }
-    const std::optional<Duration> actualDuration = estimateWorkDuration(false);
-    if (actualDuration.has_value()) {
-        std::lock_guard lock(mPowerHalMutex);
-        HalWrapper* const halWrapper = getPowerHal();
-        if (halWrapper != nullptr) {
-            halWrapper->sendActualWorkDuration(*actualDuration + sTargetSafetyMargin,
-                                               TimePoint::now());
-        }
-    }
-}
-
-void PowerAdvisor::sendPredictedWorkDuration() {
-    if (!mBootFinished || !usePowerHintSession()) {
-        ALOGV("Actual work duration power hint cannot be sent, skipping");
+    ATRACE_CALL();
+    std::optional<Duration> actualDuration = estimateWorkDuration();
+    if (!actualDuration.has_value() || actualDuration < 0ns || !ensurePowerHintSessionRunning()) {
+        ALOGV("Failed to send actual work duration, skipping");
         return;
     }
+    actualDuration = std::make_optional(*actualDuration + sTargetSafetyMargin);
+    mActualDuration = actualDuration;
+    WorkDuration duration;
+    duration.durationNanos = actualDuration->ns();
+    duration.timeStampNanos = TimePoint::now().ns();
+    mHintSessionQueue.push_back(duration);
 
-    const std::optional<Duration> predictedDuration = estimateWorkDuration(true);
-    if (predictedDuration.has_value()) {
-        std::lock_guard lock(mPowerHalMutex);
-        HalWrapper* const halWrapper = getPowerHal();
-        if (halWrapper != nullptr) {
-            halWrapper->sendActualWorkDuration(*predictedDuration + sTargetSafetyMargin,
-                                               TimePoint::now());
+    if (sTraceHintSessionData) {
+        ATRACE_INT64("Measured duration", actualDuration->ns());
+        ATRACE_INT64("Target error term", Duration{*actualDuration - mTargetDuration}.ns());
+        ATRACE_INT64("Reported duration", actualDuration->ns());
+        ATRACE_INT64("Reported target", mLastTargetDurationSent.ns());
+        ATRACE_INT64("Reported target error term",
+                     Duration{*actualDuration - mLastTargetDurationSent}.ns());
+    }
+
+    ALOGV("Sending actual work duration of: %" PRId64 " on reported target: %" PRId64
+          " with error: %" PRId64,
+          actualDuration->ns(), mLastTargetDurationSent.ns(),
+          Duration{*actualDuration - mLastTargetDurationSent}.ns());
+
+    {
+        std::lock_guard lock(mHintSessionMutex);
+        auto ret = mHintSession->reportActualWorkDuration(mHintSessionQueue);
+        if (!ret.isOk()) {
+            ALOGW("Failed to report actual work durations with error: %s",
+                  ret.exceptionMessage().c_str());
+            mHintSessionRunning = false;
+            return;
         }
     }
+    mHintSessionQueue.clear();
 }
 
-void PowerAdvisor::enablePowerHint(bool enabled) {
-    mPowerHintEnabled = enabled;
+void PowerAdvisor::enablePowerHintSession(bool enabled) {
+    mHintSessionEnabled = enabled;
 }
 
 bool PowerAdvisor::startPowerHintSession(const std::vector<int32_t>& threadIds) {
-    if (!usePowerHintSession()) {
-        ALOGI("Power hint session cannot be started, skipping");
+    if (!mBootFinished.load()) {
+        return false;
     }
+    if (!usePowerHintSession()) {
+        ALOGI("Cannot start power hint session: disabled or unsupported");
+        return false;
+    }
+    if (mHintSessionRunning) {
+        ALOGE("Cannot start power hint session: already running");
+        return false;
+    }
+    LOG_ALWAYS_FATAL_IF(threadIds.empty(), "No thread IDs provided to power hint session!");
     {
-        std::lock_guard lock(mPowerHalMutex);
-        HalWrapper* halWrapper = getPowerHal();
-        if (halWrapper != nullptr && usePowerHintSession()) {
-            halWrapper->setPowerHintSessionThreadIds(threadIds);
-            mPowerHintSessionRunning = halWrapper->startPowerHintSession();
+        std::lock_guard lock(mHintSessionMutex);
+        mHintSession = nullptr;
+        mHintSessionThreadIds = threadIds;
+
+        auto ret = getPowerHal().createHintSession(getpid(), static_cast<int32_t>(getuid()),
+                                                   threadIds, mTargetDuration.ns());
+
+        if (ret.isOk()) {
+            mHintSessionRunning = true;
+            mHintSession = ret.value();
         }
     }
-    return mPowerHintSessionRunning;
+    return mHintSessionRunning;
 }
 
 void PowerAdvisor::setGpuFenceTime(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime) {
@@ -356,13 +395,13 @@
     return sortedDisplays;
 }
 
-std::optional<Duration> PowerAdvisor::estimateWorkDuration(bool earlyHint) {
-    if (earlyHint && (!mExpectedPresentTimes.isFull() || !mCommitStartTimes.isFull())) {
+std::optional<Duration> PowerAdvisor::estimateWorkDuration() {
+    if (!mExpectedPresentTimes.isFull() || !mCommitStartTimes.isFull()) {
         return std::nullopt;
     }
 
     // Tracks when we finish presenting to hwc
-    TimePoint estimatedEndTime = mCommitStartTimes[0];
+    TimePoint estimatedHwcEndTime = mCommitStartTimes[0];
 
     // How long we spent this frame not doing anything, waiting for fences or vsync
     Duration idleDuration = 0ns;
@@ -375,21 +414,11 @@
     // used to accumulate gpu time as we iterate over the active displays
     std::optional<TimePoint> estimatedGpuEndTime;
 
-    // If we're predicting at the start of the frame, we use last frame as our reference point
-    // If we're predicting at the end of the frame, we use the current frame as a reference point
-    TimePoint referenceFrameStartTime = (earlyHint ? mCommitStartTimes[-1] : mCommitStartTimes[0]);
-
-    // When the prior frame should be presenting to the display
-    // If we're predicting at the start of the frame, we use last frame's expected present time
-    // If we're predicting at the end of the frame, the present fence time is already known
-    TimePoint lastFramePresentTime =
-            (earlyHint ? mExpectedPresentTimes[-1] : mLastPresentFenceTime);
-
     // The timing info for the previously calculated display, if there was one
-    std::optional<DisplayTimeline> previousDisplayReferenceTiming;
+    std::optional<DisplayTimeline> previousDisplayTiming;
     std::vector<DisplayId>&& displayIds =
             getOrderedDisplayIds(&DisplayTimingData::hwcPresentStartTime);
-    DisplayTimeline referenceTiming, estimatedTiming;
+    DisplayTimeline displayTiming;
 
     // Iterate over the displays that use hwc in the same order they are presented
     for (DisplayId displayId : displayIds) {
@@ -399,35 +428,26 @@
 
         auto& displayData = mDisplayTimingData.at(displayId);
 
-        // mLastPresentFenceTime should always be the time of the reference frame, since it will be
-        // the previous frame's present fence if called at the start, and current frame's if called
-        // at the end
-        referenceTiming = displayData.calculateDisplayTimeline(mLastPresentFenceTime);
+        displayTiming = displayData.calculateDisplayTimeline(mLastPresentFenceTime);
 
         // If this is the first display, include the duration before hwc present starts
-        if (!previousDisplayReferenceTiming.has_value()) {
-            estimatedEndTime += referenceTiming.hwcPresentStartTime - referenceFrameStartTime;
+        if (!previousDisplayTiming.has_value()) {
+            estimatedHwcEndTime += displayTiming.hwcPresentStartTime - mCommitStartTimes[0];
         } else { // Otherwise add the time since last display's hwc present finished
-            estimatedEndTime += referenceTiming.hwcPresentStartTime -
-                    previousDisplayReferenceTiming->hwcPresentEndTime;
+            estimatedHwcEndTime +=
+                    displayTiming.hwcPresentStartTime - previousDisplayTiming->hwcPresentEndTime;
         }
 
-        // Late hint can re-use reference timing here since it's estimating its own reference frame
-        estimatedTiming = earlyHint
-                ? referenceTiming.estimateTimelineFromReference(lastFramePresentTime,
-                                                                estimatedEndTime)
-                : referenceTiming;
-
         // Update predicted present finish time with this display's present time
-        estimatedEndTime = estimatedTiming.hwcPresentEndTime;
+        estimatedHwcEndTime = displayTiming.hwcPresentEndTime;
 
         // Track how long we spent waiting for the fence, can be excluded from the timing estimate
-        idleDuration += estimatedTiming.probablyWaitsForPresentFence
-                ? lastFramePresentTime - estimatedTiming.presentFenceWaitStartTime
+        idleDuration += displayTiming.probablyWaitsForPresentFence
+                ? mLastPresentFenceTime - displayTiming.presentFenceWaitStartTime
                 : 0ns;
 
         // Track how long we spent waiting to present, can be excluded from the timing estimate
-        idleDuration += earlyHint ? 0ns : referenceTiming.hwcPresentDelayDuration;
+        idleDuration += displayTiming.hwcPresentDelayDuration;
 
         // Estimate the reference frame's gpu timing
         auto gpuTiming = displayData.estimateGpuTiming(previousValidGpuEndTime);
@@ -435,24 +455,24 @@
             previousValidGpuEndTime = gpuTiming->startTime + gpuTiming->duration;
 
             // Estimate the prediction frame's gpu end time from the reference frame
-            estimatedGpuEndTime = std::max(estimatedTiming.hwcPresentStartTime,
+            estimatedGpuEndTime = std::max(displayTiming.hwcPresentStartTime,
                                            estimatedGpuEndTime.value_or(TimePoint{0ns})) +
                     gpuTiming->duration;
         }
-        previousDisplayReferenceTiming = referenceTiming;
+        previousDisplayTiming = displayTiming;
     }
     ATRACE_INT64("Idle duration", idleDuration.ns());
 
-    TimePoint estimatedFlingerEndTime = earlyHint ? estimatedEndTime : mLastSfPresentEndTime;
+    TimePoint estimatedFlingerEndTime = mLastSfPresentEndTime;
 
     // Don't count time spent idly waiting in the estimate as we could do more work in that time
-    estimatedEndTime -= idleDuration;
+    estimatedHwcEndTime -= idleDuration;
     estimatedFlingerEndTime -= idleDuration;
 
     // We finish the frame when both present and the gpu are done, so wait for the later of the two
     // Also add the frame delay duration since the target did not move while we were delayed
     Duration totalDuration = mFrameDelayDuration +
-            std::max(estimatedEndTime, estimatedGpuEndTime.value_or(TimePoint{0ns})) -
+            std::max(estimatedHwcEndTime, estimatedGpuEndTime.value_or(TimePoint{0ns})) -
             mCommitStartTimes[0];
 
     // We finish SurfaceFlinger when post-composition finishes, so add that in here
@@ -467,10 +487,7 @@
 
 Duration PowerAdvisor::combineTimingEstimates(Duration totalDuration, Duration flingerDuration) {
     Duration targetDuration{0ns};
-    {
-        std::lock_guard lock(mPowerHalMutex);
-        targetDuration = *getPowerHal()->getTargetWorkDuration();
-    }
+    targetDuration = mTargetDuration;
     if (!mTotalFrameTargetDuration.has_value()) return flingerDuration;
 
     // Normalize total to the flinger target (vsync period) since that's how often we actually send
@@ -480,26 +497,6 @@
     return std::max(flingerDuration, normalizedTotalDuration);
 }
 
-PowerAdvisor::DisplayTimeline PowerAdvisor::DisplayTimeline::estimateTimelineFromReference(
-        TimePoint fenceTime, TimePoint displayStartTime) {
-    DisplayTimeline estimated;
-    estimated.hwcPresentStartTime = displayStartTime;
-
-    // We don't predict waiting for vsync alignment yet
-    estimated.hwcPresentDelayDuration = 0ns;
-
-    // How long we expect to run before we start waiting for the fence
-    // For now just re-use last frame's post-present duration and assume it will not change much
-    // Excludes time spent waiting for vsync since that's not going to be consistent
-    estimated.presentFenceWaitStartTime = estimated.hwcPresentStartTime +
-            (presentFenceWaitStartTime - (hwcPresentStartTime + hwcPresentDelayDuration));
-    estimated.probablyWaitsForPresentFence = fenceTime > estimated.presentFenceWaitStartTime;
-    estimated.hwcPresentEndTime = postPresentFenceHwcPresentDuration +
-            (estimated.probablyWaitsForPresentFence ? fenceTime
-                                                    : estimated.presentFenceWaitStartTime);
-    return estimated;
-}
-
 PowerAdvisor::DisplayTimeline PowerAdvisor::DisplayTimingData::calculateDisplayTimeline(
         TimePoint fenceTime) {
     DisplayTimeline timeline;
@@ -560,321 +557,17 @@
     return GpuTimeline{.duration = gpuDuration, .startTime = latestGpuStartTime};
 }
 
-class HidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
-public:
-    HidlPowerHalWrapper(sp<V1_3::IPower> powerHal) : mPowerHal(std::move(powerHal)) {}
-
-    ~HidlPowerHalWrapper() override = default;
-
-    static std::unique_ptr<HalWrapper> connect() {
-        // Power HAL 1.3 is not guaranteed to be available, thus we need to query
-        // Power HAL 1.0 first and try to cast it to Power HAL 1.3.
-        sp<V1_3::IPower> powerHal = nullptr;
-        sp<V1_0::IPower> powerHal_1_0 = V1_0::IPower::getService();
-        if (powerHal_1_0 != nullptr) {
-            // Try to cast to Power HAL 1.3
-            powerHal = V1_3::IPower::castFrom(powerHal_1_0);
-            if (powerHal == nullptr) {
-                ALOGW("No Power HAL 1.3 service in system, disabling PowerAdvisor");
-            } else {
-                ALOGI("Loaded Power HAL 1.3 service");
-            }
-        } else {
-            ALOGW("No Power HAL found, disabling PowerAdvisor");
-        }
-
-        if (powerHal == nullptr) {
-            return nullptr;
-        }
-
-        return std::make_unique<HidlPowerHalWrapper>(std::move(powerHal));
-    }
-
-    bool setExpensiveRendering(bool enabled) override {
-        ALOGV("HIDL setExpensiveRendering %s", enabled ? "T" : "F");
-        auto ret = mPowerHal->powerHintAsync_1_3(PowerHint::EXPENSIVE_RENDERING, enabled);
-        if (ret.isOk()) {
-            traceExpensiveRendering(enabled);
-        }
-        return ret.isOk();
-    }
-
-    bool notifyDisplayUpdateImminentAndCpuReset() override {
-        // Power HAL 1.x doesn't have a notification for this
-        ALOGV("HIDL notifyUpdateImminent received but can't send");
-        return true;
-    }
-
-    bool supportsPowerHintSession() override { return false; }
-
-    bool isPowerHintSessionRunning() override { return false; }
-
-    void restartPowerHintSession() override {}
-
-    void setPowerHintSessionThreadIds(const std::vector<int32_t>&) override {}
-
-    bool startPowerHintSession() override { return false; }
-
-    void setTargetWorkDuration(Duration) override {}
-
-    void sendActualWorkDuration(Duration, TimePoint) override {}
-
-    bool shouldReconnectHAL() override { return false; }
-
-    std::vector<int32_t> getPowerHintSessionThreadIds() override { return std::vector<int32_t>{}; }
-
-    std::optional<Duration> getTargetWorkDuration() override { return std::nullopt; }
-
-private:
-    const sp<V1_3::IPower> mPowerHal = nullptr;
-};
-
-AidlPowerHalWrapper::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() {
-    if (mPowerHintSession != nullptr) {
-        mPowerHintSession->close();
-        mPowerHintSession = nullptr;
-    }
-}
-
-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::notifyDisplayUpdateImminentAndCpuReset() {
-    ALOGV("AIDL notifyDisplayUpdateImminentAndCpuReset");
-    if (isPowerHintSessionRunning()) {
-        mPowerHintSession->sendHint(SessionHint::CPU_LOAD_RESET);
-    }
-
-    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.ns(),
-                                            &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();
-}
-
-void AidlPowerHalWrapper::setTargetWorkDuration(Duration targetDuration) {
-    ATRACE_CALL();
-    mTargetDuration = targetDuration;
-    if (sTraceHintSessionData) ATRACE_INT64("Time target", targetDuration.ns());
-    if (isPowerHintSessionRunning() && (targetDuration != mLastTargetDurationSent)) {
-        ALOGV("Sending target time: %" PRId64 "ns", targetDuration.ns());
-        mLastTargetDurationSent = targetDuration;
-        auto ret = mPowerHintSession->updateTargetWorkDuration(targetDuration.ns());
-        if (!ret.isOk()) {
-            ALOGW("Failed to set power hint target work duration with error: %s",
-                  ret.exceptionMessage().c_str());
-            mShouldReconnectHal = true;
-        }
-    }
-}
-
-void AidlPowerHalWrapper::sendActualWorkDuration(Duration actualDuration, TimePoint timestamp) {
-    ATRACE_CALL();
-    if (actualDuration < 0ns || !isPowerHintSessionRunning()) {
-        ALOGV("Failed to send actual work duration, skipping");
-        return;
-    }
-    mActualDuration = actualDuration;
-    WorkDuration duration;
-    duration.durationNanos = actualDuration.ns();
-    duration.timeStampNanos = timestamp.ns();
-    mPowerHintQueue.push_back(duration);
-
-    if (sTraceHintSessionData) {
-        ATRACE_INT64("Measured duration", actualDuration.ns());
-        ATRACE_INT64("Target error term", Duration{actualDuration - mTargetDuration}.ns());
-
-        ATRACE_INT64("Reported duration", actualDuration.ns());
-        ATRACE_INT64("Reported target", mLastTargetDurationSent.ns());
-        ATRACE_INT64("Reported target error term",
-                     Duration{actualDuration - mLastTargetDurationSent}.ns());
-    }
-
-    ALOGV("Sending actual work duration of: %" PRId64 " on reported target: %" PRId64
-          " with error: %" PRId64,
-          actualDuration.ns(), mLastTargetDurationSent.ns(),
-          Duration{actualDuration - mLastTargetDurationSent}.ns());
-
-    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();
-}
-
-bool AidlPowerHalWrapper::shouldReconnectHAL() {
-    return mShouldReconnectHal;
-}
-
-std::vector<int32_t> AidlPowerHalWrapper::getPowerHintSessionThreadIds() {
-    return mPowerHintThreadIds;
-}
-
-std::optional<Duration> AidlPowerHalWrapper::getTargetWorkDuration() {
-    return mTargetDuration;
-}
-
-const bool AidlPowerHalWrapper::sTraceHintSessionData =
+const bool PowerAdvisor::sTraceHintSessionData =
         base::GetBoolProperty(std::string("debug.sf.trace_hint_sessions"), false);
 
 const Duration PowerAdvisor::sTargetSafetyMargin = std::chrono::microseconds(
         base::GetIntProperty<int64_t>("debug.sf.hint_margin_us",
                                       ticks<std::micro>(PowerAdvisor::kDefaultTargetSafetyMargin)));
 
-PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() {
-    if (!mHasHal) {
-        return nullptr;
-    }
-
-    // Grab old hint session values before we destroy any existing wrapper
-    std::vector<int32_t> oldPowerHintSessionThreadIds;
-    std::optional<Duration> oldTargetWorkDuration;
-
-    if (mHalWrapper != nullptr) {
-        oldPowerHintSessionThreadIds = mHalWrapper->getPowerHintSessionThreadIds();
-        oldTargetWorkDuration = mHalWrapper->getTargetWorkDuration();
-    }
-
-    // If we used to have a HAL, but it stopped responding, attempt to reconnect
-    if (mReconnectPowerHal) {
-        mHalWrapper = nullptr;
-        mReconnectPowerHal = false;
-    }
-
-    if (mHalWrapper != nullptr) {
-        auto wrapper = mHalWrapper.get();
-        // If the wrapper is fine, return it, but if it indicates a reconnect, remake it
-        if (!wrapper->shouldReconnectHAL()) {
-            return wrapper;
-        }
-        ALOGD("Reconnecting Power HAL");
-        mHalWrapper = nullptr;
-    }
-
-    // At this point, we know for sure there is no running session
-    mPowerHintSessionRunning = false;
-
-    // First attempt to connect to the AIDL Power HAL
-    mHalWrapper = AidlPowerHalWrapper::connect();
-
-    // If that didn't succeed, attempt to connect to the HIDL Power HAL
-    if (mHalWrapper == nullptr) {
-        mHalWrapper = HidlPowerHalWrapper::connect();
-    } else {
-        ALOGD("Successfully connecting AIDL Power HAL");
-        // If AIDL, pass on any existing hint session values
-        mHalWrapper->setPowerHintSessionThreadIds(oldPowerHintSessionThreadIds);
-        // Only set duration and start if duration is defined
-        if (oldTargetWorkDuration.has_value()) {
-            mHalWrapper->setTargetWorkDuration(*oldTargetWorkDuration);
-            // Only start if possible to run and both threadids and duration are defined
-            if (usePowerHintSession() && !oldPowerHintSessionThreadIds.empty()) {
-                mPowerHintSessionRunning = mHalWrapper->startPowerHintSession();
-            }
-        }
-    }
-
-    // If we make it to this point and still don't have a HAL, it's unlikely we
-    // will, so stop trying
-    if (mHalWrapper == nullptr) {
-        mHasHal = false;
-    }
-
-    return mHalWrapper.get();
+power::PowerHalController& PowerAdvisor::getPowerHal() {
+    static std::once_flag halFlag;
+    std::call_once(halFlag, [this] { mPowerHal->init(); });
+    return *mPowerHal;
 }
 
 } // namespace impl
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
index c4cfdc3..7a0d426 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -27,6 +27,7 @@
 
 #include <android/hardware/power/IPower.h>
 #include <compositionengine/impl/OutputCompositionState.h>
+#include <powermanager/PowerHalController.h>
 #include <scheduler/Time.h>
 #include <ui/DisplayIdentification.h>
 #include "../Scheduler/OneShotTimer.h"
@@ -52,15 +53,14 @@
     // Checks both if it supports and if it's enabled
     virtual bool usePowerHintSession() = 0;
     virtual bool supportsPowerHintSession() = 0;
-    virtual bool isPowerHintSessionRunning() = 0;
+
+    virtual bool ensurePowerHintSessionRunning() = 0;
     // Sends a power hint that updates to the target work duration for the frame
-    virtual void setTargetWorkDuration(Duration targetDuration) = 0;
+    virtual void updateTargetWorkDuration(Duration targetDuration) = 0;
     // Sends a power hint for the actual known work duration at the end of the frame
-    virtual void sendActualWorkDuration() = 0;
-    // Sends a power hint for the upcoming frame predicted from previous frame timing
-    virtual void sendPredictedWorkDuration() = 0;
+    virtual void reportActualWorkDuration() = 0;
     // Sets whether the power hint session is enabled
-    virtual void enablePowerHint(bool enabled) = 0;
+    virtual void enablePowerHintSession(bool enabled) = 0;
     // Initializes the power hint session
     virtual bool startPowerHintSession(const std::vector<int32_t>& threadIds) = 0;
     // Provides PowerAdvisor with a copy of the gpu fence so it can determine the gpu end time
@@ -101,24 +101,6 @@
 // full state of the system when sending out power hints to things like the GPU.
 class PowerAdvisor final : public Hwc2::PowerAdvisor {
 public:
-    class HalWrapper {
-    public:
-        virtual ~HalWrapper() = default;
-
-        virtual bool setExpensiveRendering(bool enabled) = 0;
-        virtual bool notifyDisplayUpdateImminentAndCpuReset() = 0;
-        virtual bool supportsPowerHintSession() = 0;
-        virtual bool isPowerHintSessionRunning() = 0;
-        virtual void restartPowerHintSession() = 0;
-        virtual void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) = 0;
-        virtual bool startPowerHintSession() = 0;
-        virtual void setTargetWorkDuration(Duration targetDuration) = 0;
-        virtual void sendActualWorkDuration(Duration actualDuration, TimePoint timestamp) = 0;
-        virtual bool shouldReconnectHAL() = 0;
-        virtual std::vector<int32_t> getPowerHintSessionThreadIds() = 0;
-        virtual std::optional<Duration> getTargetWorkDuration() = 0;
-    };
-
     PowerAdvisor(SurfaceFlinger& flinger);
     ~PowerAdvisor() override;
 
@@ -129,11 +111,10 @@
     void notifyDisplayUpdateImminentAndCpuReset() override;
     bool usePowerHintSession() override;
     bool supportsPowerHintSession() override;
-    bool isPowerHintSessionRunning() override;
-    void setTargetWorkDuration(Duration targetDuration) override;
-    void sendActualWorkDuration() override;
-    void sendPredictedWorkDuration() override;
-    void enablePowerHint(bool enabled) override;
+    bool ensurePowerHintSessionRunning() override;
+    void updateTargetWorkDuration(Duration targetDuration) override;
+    void reportActualWorkDuration() override;
+    void enablePowerHintSession(bool enabled) override;
     bool startPowerHintSession(const std::vector<int32_t>& threadIds) override;
     void setGpuFenceTime(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime);
     void setHwcValidateTiming(DisplayId displayId, TimePoint validateStartTime,
@@ -155,15 +136,7 @@
 private:
     friend class PowerAdvisorTest;
 
-    // Tracks if powerhal exists
-    bool mHasHal = true;
-    // Holds the hal wrapper for getPowerHal
-    std::unique_ptr<HalWrapper> mHalWrapper GUARDED_BY(mPowerHalMutex) = nullptr;
-
-    HalWrapper* getPowerHal() REQUIRES(mPowerHalMutex);
-    bool mReconnectPowerHal GUARDED_BY(mPowerHalMutex) = false;
-    std::mutex mPowerHalMutex;
-
+    std::unique_ptr<power::PowerHalController> mPowerHal;
     std::atomic_bool mBootFinished = false;
 
     std::unordered_set<DisplayId> mExpensiveDisplays;
@@ -189,9 +162,6 @@
         Duration postPresentFenceHwcPresentDuration{0ns};
         // Are we likely to have waited for the present fence during composition
         bool probablyWaitsForPresentFence = false;
-        // Estimate one frame's timeline from that of a previous frame
-        DisplayTimeline estimateTimelineFromReference(TimePoint fenceTime,
-                                                      TimePoint displayStartTime);
     };
 
     struct GpuTimeline {
@@ -243,8 +213,7 @@
     std::vector<DisplayId> getOrderedDisplayIds(
             std::optional<TimePoint> DisplayTimingData::*sortBy);
     // Estimates a frame's total work duration including gpu time.
-    // Runs either at the beginning or end of a frame, using the most recent data available
-    std::optional<Duration> estimateWorkDuration(bool earlyHint);
+    std::optional<Duration> estimateWorkDuration();
     // There are two different targets and actual work durations we care about,
     // this normalizes them together and takes the max of the two
     Duration combineTimingEstimates(Duration totalDuration, Duration flingerDuration);
@@ -268,9 +237,32 @@
     // Updated list of display IDs
     std::vector<DisplayId> mDisplayIds;
 
-    std::optional<bool> mPowerHintEnabled;
-    std::optional<bool> mSupportsPowerHint;
-    bool mPowerHintSessionRunning = false;
+    // Ensure powerhal connection is initialized
+    power::PowerHalController& getPowerHal();
+
+    std::optional<bool> mHintSessionEnabled;
+    std::optional<bool> mSupportsHintSession;
+    bool mHintSessionRunning = false;
+
+    std::mutex mHintSessionMutex;
+    sp<hardware::power::IPowerHintSession> mHintSession GUARDED_BY(mHintSessionMutex) = nullptr;
+
+    // Initialize to true so we try to call, to check if it's supported
+    bool mHasExpensiveRendering = true;
+    bool mHasDisplayUpdateImminent = true;
+    // Queue of actual durations saved to report
+    std::vector<hardware::power::WorkDuration> mHintSessionQueue;
+    // The latest values we have received for target and actual
+    Duration mTargetDuration = kDefaultTargetDuration;
+    std::optional<Duration> mActualDuration;
+    // The list of thread ids, stored so we can restart the session from this class if needed
+    std::vector<int32_t> mHintSessionThreadIds;
+    Duration mLastTargetDurationSent = kDefaultTargetDuration;
+    // Whether we should emit ATRACE_INT data for hint sessions
+    static const bool sTraceHintSessionData;
+
+    // Default target duration for the hint session
+    static constexpr const Duration kDefaultTargetDuration{16ms};
 
     // An adjustable safety margin which pads the "actual" value sent to PowerHAL,
     // encouraging more aggressive boosting to give SurfaceFlinger a larger margin for error
@@ -282,56 +274,6 @@
     static constexpr const Duration kFenceWaitStartDelaySkippedValidate{250us};
 };
 
-class AidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
-public:
-    explicit AidlPowerHalWrapper(sp<hardware::power::IPower> powerHal);
-    ~AidlPowerHalWrapper() override;
-
-    static std::unique_ptr<HalWrapper> connect();
-
-    bool setExpensiveRendering(bool enabled) override;
-    bool notifyDisplayUpdateImminentAndCpuReset() override;
-    bool supportsPowerHintSession() override;
-    bool isPowerHintSessionRunning() override;
-    void restartPowerHintSession() override;
-    void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) override;
-    bool startPowerHintSession() override;
-    void setTargetWorkDuration(Duration targetDuration) override;
-    void sendActualWorkDuration(Duration actualDuration, TimePoint timestamp) override;
-    bool shouldReconnectHAL() override;
-    std::vector<int32_t> getPowerHintSessionThreadIds() override;
-    std::optional<Duration> getTargetWorkDuration() override;
-
-private:
-    friend class AidlPowerHalWrapperTest;
-
-    bool checkPowerHintSessionSupported();
-    void closePowerHintSession();
-
-    const sp<hardware::power::IPower> mPowerHal = nullptr;
-    bool mHasExpensiveRendering = false;
-    bool mHasDisplayUpdateImminent = false;
-    // Used to indicate an error state and need for reconstruction
-    bool mShouldReconnectHal = false;
-
-    // Power hint session data
-
-    // Concurrent access for this is protected by mPowerHalMutex
-    sp<hardware::power::IPowerHintSession> mPowerHintSession = nullptr;
-    // Queue of actual durations saved to report
-    std::vector<hardware::power::WorkDuration> mPowerHintQueue;
-    // The latest values we have received for target and actual
-    Duration mTargetDuration = kDefaultTargetDuration;
-    std::optional<Duration> 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 = false;
-    Duration mLastTargetDurationSent = kDefaultTargetDuration;
-    // Whether we should emit ATRACE_INT data for hint sessions
-    static const bool sTraceHintSessionData;
-    static constexpr Duration kDefaultTargetDuration{16ms};
-};
-
 } // namespace impl
 } // namespace Hwc2
 } // namespace android