Loading services/surfaceflinger/Android.bp +1 −1 Original line number Diff line number Diff line Loading @@ -45,7 +45,7 @@ cc_defaults { "android.hardware.graphics.composer@2.4", "android.hardware.power@1.0", "android.hardware.power@1.3", "android.hardware.power-V1-cpp", "android.hardware.power-V2-cpp", "libbase", "libbinder", "libcutils", Loading services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h +15 −5 Original line number Diff line number Diff line Loading @@ -29,11 +29,21 @@ public: PowerAdvisor(); ~PowerAdvisor() override; MOCK_METHOD0(init, void()); MOCK_METHOD0(onBootFinished, void()); MOCK_METHOD2(setExpensiveRenderingExpected, void(DisplayId displayId, bool expected)); MOCK_METHOD0(isUsingExpensiveRendering, bool()); MOCK_METHOD0(notifyDisplayUpdateImminent, void()); MOCK_METHOD(void, init, (), (override)); MOCK_METHOD(void, onBootFinished, (), (override)); MOCK_METHOD(void, setExpensiveRenderingExpected, (DisplayId displayId, bool expected), (override)); MOCK_METHOD(bool, isUsingExpensiveRendering, (), (override)); MOCK_METHOD(void, notifyDisplayUpdateImminent, (), (override)); MOCK_METHOD(bool, usePowerHintSession, (), (override)); MOCK_METHOD(bool, supportsPowerHintSession, (), (override)); MOCK_METHOD(bool, isPowerHintSessionRunning, (), (override)); MOCK_METHOD(void, setTargetWorkDuration, (int64_t targetDurationNanos), (override)); MOCK_METHOD(void, setPowerHintSessionThreadIds, (const std::vector<int32_t>& threadIds), (override)); MOCK_METHOD(void, sendActualWorkDuration, (int64_t actualDurationNanos, nsecs_t timestamp), (override)); MOCK_METHOD(void, enablePowerHint, (bool enabled), (override)); }; } // namespace mock Loading services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp +291 −3 Original line number Diff line number Diff line Loading @@ -19,7 +19,10 @@ #undef LOG_TAG #define LOG_TAG "PowerAdvisor" #include <unistd.h> #include <cinttypes> #include <cstdint> #include <optional> #include <android-base/properties.h> #include <utils/Log.h> Loading @@ -27,6 +30,9 @@ #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> #include <binder/IServiceManager.h> #include "../SurfaceFlingerProperties.h" Loading @@ -47,10 +53,14 @@ 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 base::GetIntProperty; using android::hardware::power::WorkDuration; using scheduler::OneShotTimer; class AidlPowerHalWrapper; PowerAdvisor::~PowerAdvisor() = default; namespace { Loading Loading @@ -83,6 +93,13 @@ void PowerAdvisor::init() { void PowerAdvisor::onBootFinished() { mBootFinished.store(true); { std::lock_guard lock(mPowerHalMutex); HalWrapper* halWrapper = getPowerHal(); if (halWrapper != nullptr && usePowerHintSession()) { mPowerHintSessionRunning = halWrapper->startPowerHintSession(); } } } void PowerAdvisor::setExpensiveRenderingExpected(DisplayId displayId, bool expected) { Loading Loading @@ -136,6 +153,80 @@ void PowerAdvisor::notifyDisplayUpdateImminent() { } } // 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 ALOGE_IF(!mPowerHintEnabled.has_value(), "Power hint session cannot be used before boot!"); return mPowerHintEnabled.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->supportsPowerHintSession(); } return *mSupportsPowerHint; } bool PowerAdvisor::isPowerHintSessionRunning() { return mPowerHintSessionRunning; } void PowerAdvisor::setTargetWorkDuration(int64_t targetDurationNanos) { // we check "supports" here not "usePowerHintSession" because this needs to work // before the session is actually running, and "use" will always fail before boot // we store the values passed in before boot to start the session with during onBootFinished if (!supportsPowerHintSession()) { ALOGV("Power hint session target duration cannot be set, skipping"); return; } { std::lock_guard lock(mPowerHalMutex); HalWrapper* const halWrapper = getPowerHal(); if (halWrapper != nullptr) { halWrapper->setTargetWorkDuration(targetDurationNanos); } } } void PowerAdvisor::setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) { // we check "supports" here not "usePowerHintSession" because this needs to wsork // before the session is actually running, and "use" will always fail before boot. // we store the values passed in before boot to start the session with during onBootFinished if (!supportsPowerHintSession()) { ALOGV("Power hint session thread ids cannot be set, skipping"); return; } { std::lock_guard lock(mPowerHalMutex); HalWrapper* const halWrapper = getPowerHal(); if (halWrapper != nullptr) { halWrapper->setPowerHintSessionThreadIds(const_cast<std::vector<int32_t>&>(threadIds)); } } } void PowerAdvisor::sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timeStampNanos) { if (!mBootFinished || !usePowerHintSession()) { ALOGV("Actual work duration power hint cannot be sent, skipping"); return; } { std::lock_guard lock(mPowerHalMutex); HalWrapper* const halWrapper = getPowerHal(); if (halWrapper != nullptr) { halWrapper->sendActualWorkDuration(actualDurationNanos, timeStampNanos); } } } // needs to be set after the flag is known but before PowerAdvisor enters onBootFinished void PowerAdvisor::enablePowerHint(bool enabled) { mPowerHintEnabled = enabled; } class HidlPowerHalWrapper : public PowerAdvisor::HalWrapper { public: HidlPowerHalWrapper(sp<V1_3::IPower> powerHal) : mPowerHal(std::move(powerHal)) {} Loading Loading @@ -178,6 +269,26 @@ public: 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(int64_t) override {} void sendActualWorkDuration(int64_t, nsecs_t) override {} bool shouldReconnectHAL() override { return false; } std::vector<int32_t> getPowerHintSessionThreadIds() override { return std::vector<int32_t>{}; } std::optional<int64_t> getTargetWorkDuration() override { return std::nullopt; } private: const sp<V1_3::IPower> mPowerHal = nullptr; }; Loading @@ -195,9 +306,21 @@ public: if (!ret.isOk()) { mHasDisplayUpdateImminent = false; } // This just gives a number not a binder status, so no .isOk() mSupportsPowerHints = mPowerHal->getInterfaceVersion() >= 2; if (mSupportsPowerHints) { mPowerHintQueue.reserve(MAX_QUEUE_SIZE); } } ~AidlPowerHalWrapper() override = default; ~AidlPowerHalWrapper() override { if (mPowerHintSession != nullptr) { mPowerHintSession->close(); mPowerHintSession = nullptr; } }; static std::unique_ptr<HalWrapper> connect() { // This only waits if the service is actually declared Loading Loading @@ -232,10 +355,147 @@ public: return ret.isOk(); } // only version 2+ of the aidl supports power hint sessions, hidl has no support bool supportsPowerHintSession() override { return mSupportsPowerHints; } 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 || !mPowerHintTargetDuration.has_value() || mPowerHintThreadIds.empty()) { ALOGV("Cannot start power hint session, skipping"); return false; } auto ret = mPowerHal->createHintSession(getpid(), static_cast<int32_t>(getuid()), mPowerHintThreadIds, *mPowerHintTargetDuration, &mPowerHintSession); if (!ret.isOk()) { ALOGW("Failed to start power hint session with error: %s", ret.exceptionToString(ret.exceptionCode()).c_str()); // Indicate to the poweradvisor that this wrapper likely needs to be remade mShouldReconnectHal = true; } return isPowerHintSessionRunning(); } bool shouldSetTargetDuration(int64_t targetDurationNanos) { if (!mLastTargetDurationSent.has_value()) { return true; } // 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)) >= ALLOWED_TARGET_DEVIATION_PERCENT; } void setTargetWorkDuration(int64_t targetDurationNanos) override { mPowerHintTargetDuration = targetDurationNanos; if (shouldSetTargetDuration(targetDurationNanos) && isPowerHintSessionRunning()) { 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 have exceeded the max queue size if (!mLastMessageReported.has_value() || mPowerHintQueue.size() >= MAX_QUEUE_SIZE) { return true; } // duration of most recent timing const double mostRecentActualDuration = static_cast<double>(mPowerHintQueue.back().durationNanos); // duration of the last timing actually reported to the powerhal const double lastReportedActualDuration = static_cast<double>(mLastMessageReported->durationNanos); // report if the change in duration from then to now exceeds the threshold return abs(1.0 - mostRecentActualDuration / lastReportedActualDuration) >= ALLOWED_ACTUAL_DEVIATION_PERCENT; } void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timeStampNanos) override { if (actualDurationNanos < 0 || !isPowerHintSessionRunning()) { ALOGV("Failed to send actual work duration, skipping"); return; } WorkDuration duration; duration.durationNanos = actualDurationNanos; duration.timeStampNanos = timeStampNanos; mPowerHintQueue.push_back(duration); // 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()) { 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(); mLastMessageReported = duration; } } bool shouldReconnectHAL() override { return mShouldReconnectHal; } std::vector<int32_t> getPowerHintSessionThreadIds() override { return mPowerHintThreadIds; } std::optional<int64_t> getTargetWorkDuration() override { return mPowerHintTargetDuration; } private: // max number of messages allowed in mPowerHintQueue before reporting is forced static constexpr int32_t MAX_QUEUE_SIZE = 15; // max percent the actual duration can vary without causing a report (eg: 0.1 = 10%) static constexpr double ALLOWED_ACTUAL_DEVIATION_PERCENT = 0.1; // max percent the target duration can vary without causing a report (eg: 0.05 = 5%) static constexpr double ALLOWED_TARGET_DEVIATION_PERCENT = 0.05; const sp<IPower> mPowerHal = nullptr; bool mHasExpensiveRendering = false; bool mHasDisplayUpdateImminent = false; bool mShouldReconnectHal = false; // used to indicate an error state and need for reconstruction // This is not thread safe, but is currently protected by mPowerHalMutex so it needs no lock sp<IPowerHintSession> mPowerHintSession = nullptr; std::vector<WorkDuration> mPowerHintQueue; // halwrapper owns these values so we can init when we want and reconnect if broken std::optional<int64_t> mPowerHintTargetDuration; std::vector<int32_t> mPowerHintThreadIds; // keep track of the last messages sent for rate limiter change detection std::optional<WorkDuration> mLastMessageReported; std::optional<int64_t> mLastTargetDurationSent; bool mSupportsPowerHints; }; PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() { Loading @@ -246,6 +506,15 @@ PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() { return nullptr; } // grab old hint session values before we destroy any existing wrapper std::vector<int32_t> oldPowerHintSessionThreadIds; std::optional<int64_t> oldTargetWorkDuration; if (sHalWrapper != nullptr) { oldPowerHintSessionThreadIds = sHalWrapper->getPowerHintSessionThreadIds(); oldTargetWorkDuration = sHalWrapper->getTargetWorkDuration(); } // If we used to have a HAL, but it stopped responding, attempt to reconnect if (mReconnectPowerHal) { sHalWrapper = nullptr; Loading @@ -253,15 +522,34 @@ PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() { } if (sHalWrapper != nullptr) { return sHalWrapper.get(); auto wrapper = sHalWrapper.get(); // if the wrapper is fine, return it, but if it indicates a reconnect, remake it if (!wrapper->shouldReconnectHAL()) { return wrapper; } sHalWrapper = nullptr; } // at this point, we know for sure there is no running session mPowerHintSessionRunning = false; // First attempt to connect to the AIDL Power HAL sHalWrapper = AidlPowerHalWrapper::connect(); // If that didn't succeed, attempt to connect to the HIDL Power HAL if (sHalWrapper == nullptr) { sHalWrapper = HidlPowerHalWrapper::connect(); } else { // if AIDL, pass on any existing hint session values // thread ids always safe to set sHalWrapper->setPowerHintSessionThreadIds(oldPowerHintSessionThreadIds); // only set duration and start if duration is defined if (oldTargetWorkDuration.has_value()) { sHalWrapper->setTargetWorkDuration(*oldTargetWorkDuration); // only start if possible to run and both threadids and duration are defined if (usePowerHintSession() && !oldPowerHintSessionThreadIds.empty()) { mPowerHintSessionRunning = sHalWrapper->startPowerHintSession(); } } } // If we make it to this point and still don't have a HAL, it's unlikely we Loading services/surfaceflinger/DisplayHardware/PowerAdvisor.h +29 −1 Original line number Diff line number Diff line Loading @@ -40,6 +40,13 @@ public: virtual void setExpensiveRenderingExpected(DisplayId displayId, bool expected) = 0; virtual bool isUsingExpensiveRendering() = 0; virtual void notifyDisplayUpdateImminent() = 0; virtual bool usePowerHintSession() = 0; virtual bool supportsPowerHintSession() = 0; virtual bool isPowerHintSessionRunning() = 0; virtual void setTargetWorkDuration(int64_t targetDurationNanos) = 0; virtual void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) = 0; virtual void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timestamp) = 0; virtual void enablePowerHint(bool enabled) = 0; }; namespace impl { Loading @@ -54,6 +61,17 @@ public: virtual bool setExpensiveRendering(bool enabled) = 0; virtual bool notifyDisplayUpdateImminent() = 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(int64_t targetDurationNanos) = 0; virtual void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timeStampNanos) = 0; virtual bool shouldReconnectHAL() = 0; virtual std::vector<int32_t> getPowerHintSessionThreadIds() = 0; virtual std::optional<int64_t> getTargetWorkDuration() = 0; }; PowerAdvisor(SurfaceFlinger& flinger); Loading @@ -62,8 +80,15 @@ public: void init() override; void onBootFinished() override; void setExpensiveRenderingExpected(DisplayId displayId, bool expected) override; bool isUsingExpensiveRendering() override { return mNotifiedExpensiveRendering; } bool isUsingExpensiveRendering() override { return mNotifiedExpensiveRendering; }; void notifyDisplayUpdateImminent() override; bool usePowerHintSession() override; bool supportsPowerHintSession() override; bool isPowerHintSessionRunning() override; void setTargetWorkDuration(int64_t targetDurationNanos) override; void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) override; void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timestamp) override; void enablePowerHint(bool enabled) override; private: HalWrapper* getPowerHal() REQUIRES(mPowerHalMutex); Loading @@ -71,6 +96,9 @@ private: std::mutex mPowerHalMutex; std::atomic_bool mBootFinished = false; std::optional<bool> mPowerHintEnabled; std::optional<bool> mSupportsPowerHint; bool mPowerHintSessionRunning = false; std::unordered_set<DisplayId> mExpensiveDisplays; bool mNotifiedExpensiveRendering = false; Loading services/surfaceflinger/SurfaceFlinger.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -709,6 +709,7 @@ void SurfaceFlinger::bootFinished() { ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) ); mFlagManager = std::make_unique<android::FlagManager>(); mPowerAdvisor.enablePowerHint(mFlagManager->use_adpf_cpu_hint()); mFrameTracer->initialize(); mFrameTimeline->onBootFinished(); Loading Loading
services/surfaceflinger/Android.bp +1 −1 Original line number Diff line number Diff line Loading @@ -45,7 +45,7 @@ cc_defaults { "android.hardware.graphics.composer@2.4", "android.hardware.power@1.0", "android.hardware.power@1.3", "android.hardware.power-V1-cpp", "android.hardware.power-V2-cpp", "libbase", "libbinder", "libcutils", Loading
services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h +15 −5 Original line number Diff line number Diff line Loading @@ -29,11 +29,21 @@ public: PowerAdvisor(); ~PowerAdvisor() override; MOCK_METHOD0(init, void()); MOCK_METHOD0(onBootFinished, void()); MOCK_METHOD2(setExpensiveRenderingExpected, void(DisplayId displayId, bool expected)); MOCK_METHOD0(isUsingExpensiveRendering, bool()); MOCK_METHOD0(notifyDisplayUpdateImminent, void()); MOCK_METHOD(void, init, (), (override)); MOCK_METHOD(void, onBootFinished, (), (override)); MOCK_METHOD(void, setExpensiveRenderingExpected, (DisplayId displayId, bool expected), (override)); MOCK_METHOD(bool, isUsingExpensiveRendering, (), (override)); MOCK_METHOD(void, notifyDisplayUpdateImminent, (), (override)); MOCK_METHOD(bool, usePowerHintSession, (), (override)); MOCK_METHOD(bool, supportsPowerHintSession, (), (override)); MOCK_METHOD(bool, isPowerHintSessionRunning, (), (override)); MOCK_METHOD(void, setTargetWorkDuration, (int64_t targetDurationNanos), (override)); MOCK_METHOD(void, setPowerHintSessionThreadIds, (const std::vector<int32_t>& threadIds), (override)); MOCK_METHOD(void, sendActualWorkDuration, (int64_t actualDurationNanos, nsecs_t timestamp), (override)); MOCK_METHOD(void, enablePowerHint, (bool enabled), (override)); }; } // namespace mock Loading
services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp +291 −3 Original line number Diff line number Diff line Loading @@ -19,7 +19,10 @@ #undef LOG_TAG #define LOG_TAG "PowerAdvisor" #include <unistd.h> #include <cinttypes> #include <cstdint> #include <optional> #include <android-base/properties.h> #include <utils/Log.h> Loading @@ -27,6 +30,9 @@ #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> #include <binder/IServiceManager.h> #include "../SurfaceFlingerProperties.h" Loading @@ -47,10 +53,14 @@ 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 base::GetIntProperty; using android::hardware::power::WorkDuration; using scheduler::OneShotTimer; class AidlPowerHalWrapper; PowerAdvisor::~PowerAdvisor() = default; namespace { Loading Loading @@ -83,6 +93,13 @@ void PowerAdvisor::init() { void PowerAdvisor::onBootFinished() { mBootFinished.store(true); { std::lock_guard lock(mPowerHalMutex); HalWrapper* halWrapper = getPowerHal(); if (halWrapper != nullptr && usePowerHintSession()) { mPowerHintSessionRunning = halWrapper->startPowerHintSession(); } } } void PowerAdvisor::setExpensiveRenderingExpected(DisplayId displayId, bool expected) { Loading Loading @@ -136,6 +153,80 @@ void PowerAdvisor::notifyDisplayUpdateImminent() { } } // 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 ALOGE_IF(!mPowerHintEnabled.has_value(), "Power hint session cannot be used before boot!"); return mPowerHintEnabled.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->supportsPowerHintSession(); } return *mSupportsPowerHint; } bool PowerAdvisor::isPowerHintSessionRunning() { return mPowerHintSessionRunning; } void PowerAdvisor::setTargetWorkDuration(int64_t targetDurationNanos) { // we check "supports" here not "usePowerHintSession" because this needs to work // before the session is actually running, and "use" will always fail before boot // we store the values passed in before boot to start the session with during onBootFinished if (!supportsPowerHintSession()) { ALOGV("Power hint session target duration cannot be set, skipping"); return; } { std::lock_guard lock(mPowerHalMutex); HalWrapper* const halWrapper = getPowerHal(); if (halWrapper != nullptr) { halWrapper->setTargetWorkDuration(targetDurationNanos); } } } void PowerAdvisor::setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) { // we check "supports" here not "usePowerHintSession" because this needs to wsork // before the session is actually running, and "use" will always fail before boot. // we store the values passed in before boot to start the session with during onBootFinished if (!supportsPowerHintSession()) { ALOGV("Power hint session thread ids cannot be set, skipping"); return; } { std::lock_guard lock(mPowerHalMutex); HalWrapper* const halWrapper = getPowerHal(); if (halWrapper != nullptr) { halWrapper->setPowerHintSessionThreadIds(const_cast<std::vector<int32_t>&>(threadIds)); } } } void PowerAdvisor::sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timeStampNanos) { if (!mBootFinished || !usePowerHintSession()) { ALOGV("Actual work duration power hint cannot be sent, skipping"); return; } { std::lock_guard lock(mPowerHalMutex); HalWrapper* const halWrapper = getPowerHal(); if (halWrapper != nullptr) { halWrapper->sendActualWorkDuration(actualDurationNanos, timeStampNanos); } } } // needs to be set after the flag is known but before PowerAdvisor enters onBootFinished void PowerAdvisor::enablePowerHint(bool enabled) { mPowerHintEnabled = enabled; } class HidlPowerHalWrapper : public PowerAdvisor::HalWrapper { public: HidlPowerHalWrapper(sp<V1_3::IPower> powerHal) : mPowerHal(std::move(powerHal)) {} Loading Loading @@ -178,6 +269,26 @@ public: 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(int64_t) override {} void sendActualWorkDuration(int64_t, nsecs_t) override {} bool shouldReconnectHAL() override { return false; } std::vector<int32_t> getPowerHintSessionThreadIds() override { return std::vector<int32_t>{}; } std::optional<int64_t> getTargetWorkDuration() override { return std::nullopt; } private: const sp<V1_3::IPower> mPowerHal = nullptr; }; Loading @@ -195,9 +306,21 @@ public: if (!ret.isOk()) { mHasDisplayUpdateImminent = false; } // This just gives a number not a binder status, so no .isOk() mSupportsPowerHints = mPowerHal->getInterfaceVersion() >= 2; if (mSupportsPowerHints) { mPowerHintQueue.reserve(MAX_QUEUE_SIZE); } } ~AidlPowerHalWrapper() override = default; ~AidlPowerHalWrapper() override { if (mPowerHintSession != nullptr) { mPowerHintSession->close(); mPowerHintSession = nullptr; } }; static std::unique_ptr<HalWrapper> connect() { // This only waits if the service is actually declared Loading Loading @@ -232,10 +355,147 @@ public: return ret.isOk(); } // only version 2+ of the aidl supports power hint sessions, hidl has no support bool supportsPowerHintSession() override { return mSupportsPowerHints; } 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 || !mPowerHintTargetDuration.has_value() || mPowerHintThreadIds.empty()) { ALOGV("Cannot start power hint session, skipping"); return false; } auto ret = mPowerHal->createHintSession(getpid(), static_cast<int32_t>(getuid()), mPowerHintThreadIds, *mPowerHintTargetDuration, &mPowerHintSession); if (!ret.isOk()) { ALOGW("Failed to start power hint session with error: %s", ret.exceptionToString(ret.exceptionCode()).c_str()); // Indicate to the poweradvisor that this wrapper likely needs to be remade mShouldReconnectHal = true; } return isPowerHintSessionRunning(); } bool shouldSetTargetDuration(int64_t targetDurationNanos) { if (!mLastTargetDurationSent.has_value()) { return true; } // 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)) >= ALLOWED_TARGET_DEVIATION_PERCENT; } void setTargetWorkDuration(int64_t targetDurationNanos) override { mPowerHintTargetDuration = targetDurationNanos; if (shouldSetTargetDuration(targetDurationNanos) && isPowerHintSessionRunning()) { 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 have exceeded the max queue size if (!mLastMessageReported.has_value() || mPowerHintQueue.size() >= MAX_QUEUE_SIZE) { return true; } // duration of most recent timing const double mostRecentActualDuration = static_cast<double>(mPowerHintQueue.back().durationNanos); // duration of the last timing actually reported to the powerhal const double lastReportedActualDuration = static_cast<double>(mLastMessageReported->durationNanos); // report if the change in duration from then to now exceeds the threshold return abs(1.0 - mostRecentActualDuration / lastReportedActualDuration) >= ALLOWED_ACTUAL_DEVIATION_PERCENT; } void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timeStampNanos) override { if (actualDurationNanos < 0 || !isPowerHintSessionRunning()) { ALOGV("Failed to send actual work duration, skipping"); return; } WorkDuration duration; duration.durationNanos = actualDurationNanos; duration.timeStampNanos = timeStampNanos; mPowerHintQueue.push_back(duration); // 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()) { 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(); mLastMessageReported = duration; } } bool shouldReconnectHAL() override { return mShouldReconnectHal; } std::vector<int32_t> getPowerHintSessionThreadIds() override { return mPowerHintThreadIds; } std::optional<int64_t> getTargetWorkDuration() override { return mPowerHintTargetDuration; } private: // max number of messages allowed in mPowerHintQueue before reporting is forced static constexpr int32_t MAX_QUEUE_SIZE = 15; // max percent the actual duration can vary without causing a report (eg: 0.1 = 10%) static constexpr double ALLOWED_ACTUAL_DEVIATION_PERCENT = 0.1; // max percent the target duration can vary without causing a report (eg: 0.05 = 5%) static constexpr double ALLOWED_TARGET_DEVIATION_PERCENT = 0.05; const sp<IPower> mPowerHal = nullptr; bool mHasExpensiveRendering = false; bool mHasDisplayUpdateImminent = false; bool mShouldReconnectHal = false; // used to indicate an error state and need for reconstruction // This is not thread safe, but is currently protected by mPowerHalMutex so it needs no lock sp<IPowerHintSession> mPowerHintSession = nullptr; std::vector<WorkDuration> mPowerHintQueue; // halwrapper owns these values so we can init when we want and reconnect if broken std::optional<int64_t> mPowerHintTargetDuration; std::vector<int32_t> mPowerHintThreadIds; // keep track of the last messages sent for rate limiter change detection std::optional<WorkDuration> mLastMessageReported; std::optional<int64_t> mLastTargetDurationSent; bool mSupportsPowerHints; }; PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() { Loading @@ -246,6 +506,15 @@ PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() { return nullptr; } // grab old hint session values before we destroy any existing wrapper std::vector<int32_t> oldPowerHintSessionThreadIds; std::optional<int64_t> oldTargetWorkDuration; if (sHalWrapper != nullptr) { oldPowerHintSessionThreadIds = sHalWrapper->getPowerHintSessionThreadIds(); oldTargetWorkDuration = sHalWrapper->getTargetWorkDuration(); } // If we used to have a HAL, but it stopped responding, attempt to reconnect if (mReconnectPowerHal) { sHalWrapper = nullptr; Loading @@ -253,15 +522,34 @@ PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() { } if (sHalWrapper != nullptr) { return sHalWrapper.get(); auto wrapper = sHalWrapper.get(); // if the wrapper is fine, return it, but if it indicates a reconnect, remake it if (!wrapper->shouldReconnectHAL()) { return wrapper; } sHalWrapper = nullptr; } // at this point, we know for sure there is no running session mPowerHintSessionRunning = false; // First attempt to connect to the AIDL Power HAL sHalWrapper = AidlPowerHalWrapper::connect(); // If that didn't succeed, attempt to connect to the HIDL Power HAL if (sHalWrapper == nullptr) { sHalWrapper = HidlPowerHalWrapper::connect(); } else { // if AIDL, pass on any existing hint session values // thread ids always safe to set sHalWrapper->setPowerHintSessionThreadIds(oldPowerHintSessionThreadIds); // only set duration and start if duration is defined if (oldTargetWorkDuration.has_value()) { sHalWrapper->setTargetWorkDuration(*oldTargetWorkDuration); // only start if possible to run and both threadids and duration are defined if (usePowerHintSession() && !oldPowerHintSessionThreadIds.empty()) { mPowerHintSessionRunning = sHalWrapper->startPowerHintSession(); } } } // If we make it to this point and still don't have a HAL, it's unlikely we Loading
services/surfaceflinger/DisplayHardware/PowerAdvisor.h +29 −1 Original line number Diff line number Diff line Loading @@ -40,6 +40,13 @@ public: virtual void setExpensiveRenderingExpected(DisplayId displayId, bool expected) = 0; virtual bool isUsingExpensiveRendering() = 0; virtual void notifyDisplayUpdateImminent() = 0; virtual bool usePowerHintSession() = 0; virtual bool supportsPowerHintSession() = 0; virtual bool isPowerHintSessionRunning() = 0; virtual void setTargetWorkDuration(int64_t targetDurationNanos) = 0; virtual void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) = 0; virtual void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timestamp) = 0; virtual void enablePowerHint(bool enabled) = 0; }; namespace impl { Loading @@ -54,6 +61,17 @@ public: virtual bool setExpensiveRendering(bool enabled) = 0; virtual bool notifyDisplayUpdateImminent() = 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(int64_t targetDurationNanos) = 0; virtual void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timeStampNanos) = 0; virtual bool shouldReconnectHAL() = 0; virtual std::vector<int32_t> getPowerHintSessionThreadIds() = 0; virtual std::optional<int64_t> getTargetWorkDuration() = 0; }; PowerAdvisor(SurfaceFlinger& flinger); Loading @@ -62,8 +80,15 @@ public: void init() override; void onBootFinished() override; void setExpensiveRenderingExpected(DisplayId displayId, bool expected) override; bool isUsingExpensiveRendering() override { return mNotifiedExpensiveRendering; } bool isUsingExpensiveRendering() override { return mNotifiedExpensiveRendering; }; void notifyDisplayUpdateImminent() override; bool usePowerHintSession() override; bool supportsPowerHintSession() override; bool isPowerHintSessionRunning() override; void setTargetWorkDuration(int64_t targetDurationNanos) override; void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) override; void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timestamp) override; void enablePowerHint(bool enabled) override; private: HalWrapper* getPowerHal() REQUIRES(mPowerHalMutex); Loading @@ -71,6 +96,9 @@ private: std::mutex mPowerHalMutex; std::atomic_bool mBootFinished = false; std::optional<bool> mPowerHintEnabled; std::optional<bool> mSupportsPowerHint; bool mPowerHintSessionRunning = false; std::unordered_set<DisplayId> mExpensiveDisplays; bool mNotifiedExpensiveRendering = false; Loading
services/surfaceflinger/SurfaceFlinger.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -709,6 +709,7 @@ void SurfaceFlinger::bootFinished() { ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) ); mFlagManager = std::make_unique<android::FlagManager>(); mPowerAdvisor.enablePowerHint(mFlagManager->use_adpf_cpu_hint()); mFrameTracer->initialize(); mFrameTimeline->onBootFinished(); Loading