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
Merged-In: I2a11779ce1f78bcf29ea0e7978cb8933e74e9f7b
(cherry picked from commit cbfe23c938226f5fa83d9b37f9f4212ee0c65a6f)
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