From ef56a15ce073be40d30836ece5c50185213b9ce6 Mon Sep 17 00:00:00 2001 From: clarencelol Date: Sun, 17 Oct 2021 13:08:18 +0800 Subject: [PATCH] sdm660-common: power-libperfmgr: Update AIDL Pixel PowerHAL * from android-12.0.0_r2 Signed-off-by: clarencelol Signed-off-by: pix106 --- power-libperfmgr/Android.bp | 25 +- power-libperfmgr/aidl/Power.cpp | 55 ++- power-libperfmgr/aidl/Power.h | 8 +- power-libperfmgr/aidl/PowerExt.cpp | 4 +- power-libperfmgr/aidl/PowerHintSession.cpp | 460 ++++++++++++++++++ power-libperfmgr/aidl/PowerHintSession.h | 119 +++++ power-libperfmgr/aidl/PowerSessionManager.cpp | 163 +++++++ power-libperfmgr/aidl/PowerSessionManager.h | 108 ++++ ...d.hardware.power-service.xiaomi_sdm660.xml | 1 + power-libperfmgr/aidl/service.cpp | 31 +- .../disp-power/InteractionHandler.cpp | 104 ++-- .../disp-power/InteractionHandler.h | 29 +- 12 files changed, 1036 insertions(+), 71 deletions(-) create mode 100644 power-libperfmgr/aidl/PowerHintSession.cpp create mode 100644 power-libperfmgr/aidl/PowerHintSession.h create mode 100644 power-libperfmgr/aidl/PowerSessionManager.cpp create mode 100644 power-libperfmgr/aidl/PowerSessionManager.h diff --git a/power-libperfmgr/Android.bp b/power-libperfmgr/Android.bp index 565244a1..f7de27a2 100644 --- a/power-libperfmgr/Android.bp +++ b/power-libperfmgr/Android.bp @@ -1,10 +1,24 @@ // // Copyright (C) 2018 The Android Open Source Project // -// SPDX-License-Identifier: Apache-2.0 +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} cc_library { - name: "libdisppower", + name: "libdisppower-xiaomi_sdm660", proprietary: true, srcs: [ "disp-power/InteractionHandler.cpp", @@ -25,19 +39,22 @@ cc_binary { vintf_fragments: ["aidl/android.hardware.power-service.xiaomi_sdm660.xml"], vendor: true, shared_libs: [ - "android.hardware.power-V1-ndk_platform", + "android.hardware.power-V2-ndk_platform", "libbase", "libcutils", "liblog", "libutils", "libbinder_ndk", - "libdisppower", + "libdisppower-xiaomi_sdm660", "libperfmgr", + "libprocessgroup", "pixel-power-ext-V1-ndk_platform", ], srcs: [ "aidl/service.cpp", "aidl/Power.cpp", "aidl/PowerExt.cpp", + "aidl/PowerHintSession.cpp", + "aidl/PowerSessionManager.cpp", ], } diff --git a/power-libperfmgr/aidl/Power.cpp b/power-libperfmgr/aidl/Power.cpp index ccbf01c6..bff53b66 100644 --- a/power-libperfmgr/aidl/Power.cpp +++ b/power-libperfmgr/aidl/Power.cpp @@ -15,7 +15,7 @@ */ #define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL) -#define LOG_TAG "android.hardware.power-service.xiaomi_sdm660-libperfmgr" +#define LOG_TAG "powerhal-libperfmgr" #include "Power.h" @@ -25,10 +25,14 @@ #include #include #include +#include #include #include +#include "PowerHintSession.h" +#include "PowerSessionManager.h" + #ifndef TAP_TO_WAKE_NODE #define TAP_TO_WAKE_NODE "/sys/touchpanel/double_tap" #endif @@ -44,45 +48,52 @@ namespace power { namespace impl { namespace pixel { +using ::aidl::google::hardware::power::impl::pixel::PowerHintSession; + constexpr char kPowerHalStateProp[] = "vendor.powerhal.state"; constexpr char kPowerHalAudioProp[] = "vendor.powerhal.audio"; constexpr char kPowerHalRenderingProp[] = "vendor.powerhal.rendering"; +constexpr char kPowerHalAdpfRateProp[] = "vendor.powerhal.adpf.rate"; +constexpr int64_t kPowerHalAdpfRateDefault = -1; Power::Power(std::shared_ptr hm) : mHintManager(hm), mInteractionHandler(nullptr), - mSustainedPerfModeOn(false) { + mSustainedPerfModeOn(false), + mAdpfRateNs( + ::android::base::GetIntProperty(kPowerHalAdpfRateProp, kPowerHalAdpfRateDefault)) { mInteractionHandler = std::make_unique(mHintManager); mInteractionHandler->Init(); std::string state = ::android::base::GetProperty(kPowerHalStateProp, ""); if (state == "SUSTAINED_PERFORMANCE") { - ALOGI("Initialize with SUSTAINED_PERFORMANCE on"); + LOG(INFO) << "Initialize with SUSTAINED_PERFORMANCE on"; mHintManager->DoHint("SUSTAINED_PERFORMANCE"); mSustainedPerfModeOn = true; } else { - ALOGI("Initialize PowerHAL"); + LOG(INFO) << "Initialize PowerHAL"; } state = ::android::base::GetProperty(kPowerHalAudioProp, ""); if (state == "AUDIO_STREAMING_LOW_LATENCY") { - ALOGI("Initialize with AUDIO_LOW_LATENCY on"); + LOG(INFO) << "Initialize with AUDIO_LOW_LATENCY on"; mHintManager->DoHint(state); } state = ::android::base::GetProperty(kPowerHalRenderingProp, ""); if (state == "EXPENSIVE_RENDERING") { - ALOGI("Initialize with EXPENSIVE_RENDERING on"); + LOG(INFO) << "Initialize with EXPENSIVE_RENDERING on"; mHintManager->DoHint("EXPENSIVE_RENDERING"); } // Now start to take powerhint - ALOGI("PowerHAL ready to process hints"); + LOG(INFO) << "PowerHAL ready to take hints, Adpf update rate: " << mAdpfRateNs; } ndk::ScopedAStatus Power::setMode(Mode type, bool enabled) { LOG(DEBUG) << "Power setMode: " << toString(type) << " to: " << enabled; ATRACE_INT(toString(type).c_str(), enabled); + PowerSessionManager::getInstance()->updateHintMode(toString(type), enabled); switch (type) { case Mode::DOUBLE_TAP_TO_WAKE: { @@ -129,7 +140,7 @@ ndk::ScopedAStatus Power::setMode(Mode type, bool enabled) { ndk::ScopedAStatus Power::isModeSupported(Mode type, bool *_aidl_return) { bool supported = mHintManager->IsHintSupported(toString(type)); - // LOW_POWER handled insides PowerHAL specifically + // DOUBLE_TAP_TO_WAKE handled insides PowerHAL specifically if (type == Mode::DOUBLE_TAP_TO_WAKE) { supported = true; } @@ -178,6 +189,34 @@ ndk::ScopedAStatus Power::isBoostSupported(Boost type, bool *_aidl_return) { return ndk::ScopedAStatus::ok(); } +ndk::ScopedAStatus Power::createHintSession(int32_t tgid, int32_t uid, + const std::vector &threadIds, + int64_t durationNanos, + std::shared_ptr *_aidl_return) { + if (mAdpfRateNs <= 0) { + *_aidl_return = nullptr; + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + if (threadIds.size() == 0) { + LOG(ERROR) << "Error: threadIds.size() shouldn't be " << threadIds.size(); + *_aidl_return = nullptr; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + std::shared_ptr session = ndk::SharedRefBase::make( + tgid, uid, threadIds, durationNanos, nanoseconds(mAdpfRateNs)); + *_aidl_return = session; + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Power::getHintSessionPreferredRate(int64_t *outNanoseconds) { + *outNanoseconds = mAdpfRateNs; + if (mAdpfRateNs <= 0) { + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + + return ndk::ScopedAStatus::ok(); +} + } // namespace pixel } // namespace impl } // namespace power diff --git a/power-libperfmgr/aidl/Power.h b/power-libperfmgr/aidl/Power.h index 94c5c153..9f973b73 100644 --- a/power-libperfmgr/aidl/Power.h +++ b/power-libperfmgr/aidl/Power.h @@ -32,8 +32,8 @@ namespace power { namespace impl { namespace pixel { -using ::InteractionHandler; using ::aidl::android::hardware::power::Boost; +using ::aidl::android::hardware::power::IPowerHintSession; using ::aidl::android::hardware::power::Mode; using ::android::perfmgr::HintManager; @@ -44,11 +44,17 @@ class Power : public ::aidl::android::hardware::power::BnPower { ndk::ScopedAStatus isModeSupported(Mode type, bool *_aidl_return) override; ndk::ScopedAStatus setBoost(Boost type, int32_t durationMs) override; ndk::ScopedAStatus isBoostSupported(Boost type, bool *_aidl_return) override; + ndk::ScopedAStatus createHintSession(int32_t tgid, int32_t uid, + const std::vector &threadIds, + int64_t durationNanos, + std::shared_ptr *_aidl_return) override; + ndk::ScopedAStatus getHintSessionPreferredRate(int64_t *outNanoseconds) override; private: std::shared_ptr mHintManager; std::unique_ptr mInteractionHandler; std::atomic mSustainedPerfModeOn; + const int64_t mAdpfRateNs; }; } // namespace pixel diff --git a/power-libperfmgr/aidl/PowerExt.cpp b/power-libperfmgr/aidl/PowerExt.cpp index 3a4eca5f..7fded31b 100644 --- a/power-libperfmgr/aidl/PowerExt.cpp +++ b/power-libperfmgr/aidl/PowerExt.cpp @@ -15,9 +15,10 @@ */ #define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL) -#define LOG_TAG "android.hardware.power-service.xiaomi_sdm660.ext-libperfmgr" +#define LOG_TAG "android.hardware.power-service.pixel.ext-libperfmgr" #include "PowerExt.h" +#include "PowerSessionManager.h" #include @@ -46,6 +47,7 @@ ndk::ScopedAStatus PowerExt::setMode(const std::string &mode, bool enabled) { } else { mHintManager->EndHint(mode); } + PowerSessionManager::getInstance()->updateHintMode(mode, enabled); return ndk::ScopedAStatus::ok(); } diff --git a/power-libperfmgr/aidl/PowerHintSession.cpp b/power-libperfmgr/aidl/PowerHintSession.cpp new file mode 100644 index 00000000..7a39dab0 --- /dev/null +++ b/power-libperfmgr/aidl/PowerHintSession.cpp @@ -0,0 +1,460 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "powerhal-libperfmgr" +#define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "PowerHintSession.h" +#include "PowerSessionManager.h" + +namespace aidl { +namespace google { +namespace hardware { +namespace power { +namespace impl { +namespace pixel { + +using ::android::base::StringPrintf; +using std::chrono::duration_cast; +using std::chrono::nanoseconds; +using std::literals::chrono_literals::operator""s; + +constexpr char kPowerHalAdpfPidPOver[] = "vendor.powerhal.adpf.pid_p.over"; +constexpr char kPowerHalAdpfPidPUnder[] = "vendor.powerhal.adpf.pid_p.under"; +constexpr char kPowerHalAdpfPidI[] = "vendor.powerhal.adpf.pid_i"; +constexpr char kPowerHalAdpfPidDOver[] = "vendor.powerhal.adpf.pid_d.over"; +constexpr char kPowerHalAdpfPidDUnder[] = "vendor.powerhal.adpf.pid_d.under"; +constexpr char kPowerHalAdpfPidIInit[] = "vendor.powerhal.adpf.pid_i.init"; +constexpr char kPowerHalAdpfPidIHighLimit[] = "vendor.powerhal.adpf.pid_i.high_limit"; +constexpr char kPowerHalAdpfPidILowLimit[] = "vendor.powerhal.adpf.pid_i.low_limit"; +constexpr char kPowerHalAdpfUclampEnable[] = "vendor.powerhal.adpf.uclamp"; +constexpr char kPowerHalAdpfUclampMinGranularity[] = "vendor.powerhal.adpf.uclamp_min.granularity"; +constexpr char kPowerHalAdpfUclampMinHighLimit[] = "vendor.powerhal.adpf.uclamp_min.high_limit"; +constexpr char kPowerHalAdpfUclampMinLowLimit[] = "vendor.powerhal.adpf.uclamp_min.low_limit"; +constexpr char kPowerHalAdpfStaleTimeFactor[] = "vendor.powerhal.adpf.stale_timeout_factor"; +constexpr char kPowerHalAdpfPSamplingWindow[] = "vendor.powerhal.adpf.p.window"; +constexpr char kPowerHalAdpfISamplingWindow[] = "vendor.powerhal.adpf.i.window"; +constexpr char kPowerHalAdpfDSamplingWindow[] = "vendor.powerhal.adpf.d.window"; + +namespace { +/* there is no glibc or bionic wrapper */ +struct sched_attr { + __u32 size; + __u32 sched_policy; + __u64 sched_flags; + __s32 sched_nice; + __u32 sched_priority; + __u64 sched_runtime; + __u64 sched_deadline; + __u64 sched_period; + __u32 sched_util_min; + __u32 sched_util_max; +}; + +static int sched_setattr(int pid, struct sched_attr *attr, unsigned int flags) { + static const bool kPowerHalAdpfUclamp = + ::android::base::GetBoolProperty(kPowerHalAdpfUclampEnable, true); + if (!kPowerHalAdpfUclamp) { + ALOGV("PowerHintSession:%s: skip", __func__); + return 0; + } + return syscall(__NR_sched_setattr, pid, attr, flags); +} + +static inline int64_t ns_to_100us(int64_t ns) { + return ns / 100000; +} + +static double getDoubleProperty(const char *prop, double value) { + std::string result = ::android::base::GetProperty(prop, std::to_string(value).c_str()); + if (!::android::base::ParseDouble(result.c_str(), &value)) { + ALOGE("PowerHintSession : failed to parse double in %s", prop); + } + return value; +} + +static double sPidPOver = getDoubleProperty(kPowerHalAdpfPidPOver, 5.0); +static double sPidPUnder = getDoubleProperty(kPowerHalAdpfPidPUnder, 3.0); +static double sPidI = getDoubleProperty(kPowerHalAdpfPidI, 0.001); +static double sPidDOver = getDoubleProperty(kPowerHalAdpfPidDOver, 500.0); +static double sPidDUnder = getDoubleProperty(kPowerHalAdpfPidDUnder, 0.0); +static const int64_t sPidIInit = + (sPidI == 0) ? 0 + : static_cast(::android::base::GetIntProperty( + kPowerHalAdpfPidIInit, 200) / + sPidI); +static const int64_t sPidIHighLimit = + (sPidI == 0) ? 0 + : static_cast(::android::base::GetIntProperty( + kPowerHalAdpfPidIHighLimit, 512) / + sPidI); +static const int64_t sPidILowLimit = + (sPidI == 0) ? 0 + : static_cast(::android::base::GetIntProperty( + kPowerHalAdpfPidILowLimit, -120) / + sPidI); +static const int32_t sUclampMinHighLimit = + ::android::base::GetUintProperty(kPowerHalAdpfUclampMinHighLimit, 512); +static const int32_t sUclampMinLowLimit = + ::android::base::GetUintProperty(kPowerHalAdpfUclampMinLowLimit, 0); +static const uint32_t sUclampMinGranularity = + ::android::base::GetUintProperty(kPowerHalAdpfUclampMinGranularity, 5); +static const int64_t sStaleTimeFactor = + ::android::base::GetUintProperty(kPowerHalAdpfStaleTimeFactor, 20); +static const int64_t sPSamplingWindow = + ::android::base::GetUintProperty(kPowerHalAdpfPSamplingWindow, 1); +static const int64_t sISamplingWindow = + ::android::base::GetUintProperty(kPowerHalAdpfISamplingWindow, 0); +static const int64_t sDSamplingWindow = + ::android::base::GetUintProperty(kPowerHalAdpfDSamplingWindow, 1); + +} // namespace + +PowerHintSession::PowerHintSession(int32_t tgid, int32_t uid, const std::vector &threadIds, + int64_t durationNanos, const nanoseconds adpfRate) + : kAdpfRate(adpfRate) { + mDescriptor = new AppHintDesc(tgid, uid, threadIds); + mDescriptor->duration = std::chrono::nanoseconds(durationNanos); + mStaleHandler = sp(new StaleHandler(this)); + mPowerManagerHandler = PowerSessionManager::getInstance(); + + if (ATRACE_ENABLED()) { + const std::string idstr = getIdString(); + std::string sz = StringPrintf("adpf.%s-target", idstr.c_str()); + ATRACE_INT(sz.c_str(), (int64_t)mDescriptor->duration.count()); + sz = StringPrintf("adpf.%s-active", idstr.c_str()); + ATRACE_INT(sz.c_str(), mDescriptor->is_active.load()); + } + PowerSessionManager::getInstance()->addPowerSession(this); + // init boost + setUclamp(sUclampMinHighLimit); + ALOGV("PowerHintSession created: %s", mDescriptor->toString().c_str()); +} + +PowerHintSession::~PowerHintSession() { + close(); + ALOGV("PowerHintSession deleted: %s", mDescriptor->toString().c_str()); + if (ATRACE_ENABLED()) { + const std::string idstr = getIdString(); + std::string sz = StringPrintf("adpf.%s-target", idstr.c_str()); + ATRACE_INT(sz.c_str(), 0); + sz = StringPrintf("adpf.%s-actl_last", idstr.c_str()); + ATRACE_INT(sz.c_str(), 0); + sz = sz = StringPrintf("adpf.%s-active", idstr.c_str()); + ATRACE_INT(sz.c_str(), 0); + } + delete mDescriptor; +} + +std::string PowerHintSession::getIdString() const { + std::string idstr = StringPrintf("%" PRId32 "-%" PRId32 "-%" PRIxPTR, mDescriptor->tgid, + mDescriptor->uid, reinterpret_cast(this) & 0xffff); + return idstr; +} + +void PowerHintSession::updateUniveralBoostMode() { + PowerHintMonitor::getInstance()->getLooper()->sendMessage(mPowerManagerHandler, NULL); +} + +int PowerHintSession::setUclamp(int32_t min, int32_t max) { + std::lock_guard guard(mLock); + min = std::max(0, min); + min = std::min(min, max); + max = std::max(0, max); + max = std::max(min, max); + if (ATRACE_ENABLED()) { + const std::string idstr = getIdString(); + std::string sz = StringPrintf("adpf.%s-min", idstr.c_str()); + ATRACE_INT(sz.c_str(), min); + } + for (const auto tid : mDescriptor->threadIds) { + sched_attr attr = {}; + attr.size = sizeof(attr); + + attr.sched_flags = (SCHED_FLAG_KEEP_ALL | SCHED_FLAG_UTIL_CLAMP); + attr.sched_util_min = min; + attr.sched_util_max = max; + + int ret = sched_setattr(tid, &attr, 0); + if (ret) { + ALOGW("sched_setattr failed for thread %d, err=%d", tid, errno); + } + ALOGV("PowerHintSession tid: %d, uclamp(%d, %d)", tid, min, max); + } + mDescriptor->current_min = min; + return 0; +} + +ndk::ScopedAStatus PowerHintSession::pause() { + if (!mDescriptor->is_active.load()) + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + // Reset to default uclamp value. + setUclamp(0); + mDescriptor->is_active.store(false); + if (ATRACE_ENABLED()) { + const std::string idstr = getIdString(); + std::string sz = StringPrintf("adpf.%s-active", idstr.c_str()); + ATRACE_INT(sz.c_str(), mDescriptor->is_active.load()); + } + updateUniveralBoostMode(); + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus PowerHintSession::resume() { + if (mDescriptor->is_active.load()) + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + mDescriptor->is_active.store(true); + mDescriptor->integral_error = std::max(sPidIInit, mDescriptor->integral_error); + // resume boost + setUclamp(sUclampMinHighLimit); + if (ATRACE_ENABLED()) { + const std::string idstr = getIdString(); + std::string sz = StringPrintf("adpf.%s-active", idstr.c_str()); + ATRACE_INT(sz.c_str(), mDescriptor->is_active.load()); + } + updateUniveralBoostMode(); + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus PowerHintSession::close() { + bool sessionClosedExpectedToBe = false; + if (!mSessionClosed.compare_exchange_strong(sessionClosedExpectedToBe, true)) { + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + PowerHintMonitor::getInstance()->getLooper()->removeMessages(mStaleHandler); + setUclamp(0); + PowerSessionManager::getInstance()->removePowerSession(this); + updateUniveralBoostMode(); + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus PowerHintSession::updateTargetWorkDuration(int64_t targetDurationNanos) { + if (targetDurationNanos <= 0) { + ALOGE("Error: targetDurationNanos(%" PRId64 ") should bigger than 0", targetDurationNanos); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + ALOGV("update target duration: %" PRId64 " ns", targetDurationNanos); + double ratio = + targetDurationNanos == 0 ? 1.0 : mDescriptor->duration.count() / targetDurationNanos; + mDescriptor->integral_error = + std::max(sPidIInit, static_cast(mDescriptor->integral_error * ratio)); + + mDescriptor->duration = std::chrono::nanoseconds(targetDurationNanos); + if (ATRACE_ENABLED()) { + const std::string idstr = getIdString(); + std::string sz = StringPrintf("adpf.%s-target", idstr.c_str()); + ATRACE_INT(sz.c_str(), (int64_t)mDescriptor->duration.count()); + } + + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus PowerHintSession::reportActualWorkDuration( + const std::vector &actualDurations) { + if (mDescriptor->duration.count() == 0LL) { + ALOGE("Expect to call updateTargetWorkDuration() first."); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + if (actualDurations.size() == 0) { + ALOGE("Error: duration.size() shouldn't be %zu.", actualDurations.size()); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + if (!mDescriptor->is_active.load()) { + ALOGE("Error: shouldn't report duration during pause state."); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + if (PowerHintMonitor::getInstance()->isRunning() && isStale()) { + if (ATRACE_ENABLED()) { + const std::string idstr = getIdString(); + std::string sz = StringPrintf("adpf.%s-stale", idstr.c_str()); + ATRACE_INT(sz.c_str(), 0); + } + mDescriptor->integral_error = std::max(sPidIInit, mDescriptor->integral_error); + } + int64_t targetDurationNanos = (int64_t)mDescriptor->duration.count(); + int64_t length = actualDurations.size(); + int64_t p_start = + sPSamplingWindow == 0 || sPSamplingWindow > length ? 0 : length - sPSamplingWindow; + int64_t i_start = + sISamplingWindow == 0 || sISamplingWindow > length ? 0 : length - sISamplingWindow; + int64_t d_start = + sDSamplingWindow == 0 || sDSamplingWindow > length ? 0 : length - sDSamplingWindow; + int64_t dt = ns_to_100us(targetDurationNanos); + int64_t err_sum = 0; + int64_t derivative_sum = 0; + for (int64_t i = std::min({p_start, i_start, d_start}); i < length; i++) { + int64_t actualDurationNanos = actualDurations[i].durationNanos; + if (std::abs(actualDurationNanos) > targetDurationNanos * 20) { + ALOGW("The actual duration is way far from the target (%" PRId64 " >> %" PRId64 ")", + actualDurationNanos, targetDurationNanos); + } + // PID control algorithm + int64_t error = ns_to_100us(actualDurationNanos - targetDurationNanos); + if (i >= d_start) { + derivative_sum += error - mDescriptor->previous_error; + } + if (i >= p_start) { + err_sum += error; + } + if (i >= i_start) { + mDescriptor->integral_error = mDescriptor->integral_error + error * dt; + mDescriptor->integral_error = std::min(sPidIHighLimit, mDescriptor->integral_error); + mDescriptor->integral_error = std::max(sPidILowLimit, mDescriptor->integral_error); + } + mDescriptor->previous_error = error; + } + int64_t pOut = static_cast((err_sum > 0 ? sPidPOver : sPidPUnder) * err_sum / + (length - p_start)); + int64_t iOut = static_cast(sPidI * mDescriptor->integral_error); + int64_t dOut = static_cast((derivative_sum > 0 ? sPidDOver : sPidDUnder) * + derivative_sum / dt / (length - d_start)); + + int64_t output = pOut + iOut + dOut; + if (ATRACE_ENABLED()) { + const std::string idstr = getIdString(); + std::string sz = StringPrintf("adpf.%s-actl_last", idstr.c_str()); + ATRACE_INT(sz.c_str(), actualDurations[length - 1].durationNanos); + sz = StringPrintf("adpf.%s-target", idstr.c_str()); + ATRACE_INT(sz.c_str(), (int64_t)mDescriptor->duration.count()); + sz = StringPrintf("adpf.%s-sample_size", idstr.c_str()); + ATRACE_INT(sz.c_str(), length); + sz = StringPrintf("adpf.%s-pid.count", idstr.c_str()); + ATRACE_INT(sz.c_str(), mDescriptor->update_count); + sz = StringPrintf("adpf.%s-pid.pOut", idstr.c_str()); + ATRACE_INT(sz.c_str(), pOut); + sz = StringPrintf("adpf.%s-pid.iOut", idstr.c_str()); + ATRACE_INT(sz.c_str(), iOut); + sz = StringPrintf("adpf.%s-pid.dOut", idstr.c_str()); + ATRACE_INT(sz.c_str(), dOut); + sz = StringPrintf("adpf.%s-pid.output", idstr.c_str()); + ATRACE_INT(sz.c_str(), output); + } + mDescriptor->update_count++; + + mStaleHandler->updateStaleTimer(); + + /* apply to all the threads in the group */ + if (output != 0) { + int next_min = + std::min(sUclampMinHighLimit, mDescriptor->current_min + static_cast(output)); + next_min = std::max(sUclampMinLowLimit, next_min); + if (std::abs(mDescriptor->current_min - next_min) > sUclampMinGranularity) { + setUclamp(next_min); + } + } + + return ndk::ScopedAStatus::ok(); +} + +std::string AppHintDesc::toString() const { + std::string out = + StringPrintf("session %" PRIxPTR "\n", reinterpret_cast(this) & 0xffff); + const int64_t durationNanos = duration.count(); + out.append(StringPrintf(" duration: %" PRId64 " ns\n", durationNanos)); + out.append(StringPrintf(" uclamp.min: %d \n", current_min)); + out.append(StringPrintf(" uid: %d, tgid: %d\n", uid, tgid)); + + out.append(" threadIds: ["); + bool first = true; + for (int tid : threadIds) { + if (!first) { + out.append(", "); + } + out.append(std::to_string(tid)); + first = false; + } + out.append("]\n"); + return out; +} + +bool PowerHintSession::isActive() { + return mDescriptor->is_active.load(); +} + +bool PowerHintSession::isStale() { + auto now = std::chrono::steady_clock::now(); + return now >= mStaleHandler->getStaleTime(); +} + +const std::vector &PowerHintSession::getTidList() const { + return mDescriptor->threadIds; +} + +void PowerHintSession::setStale() { + if (ATRACE_ENABLED()) { + const std::string idstr = getIdString(); + std::string sz = StringPrintf("adpf.%s-stale", idstr.c_str()); + ATRACE_INT(sz.c_str(), 1); + } + // Reset to default uclamp value. + setUclamp(0); + // Deliver a task to check if all sessions are inactive. + updateUniveralBoostMode(); +} + +void PowerHintSession::StaleHandler::updateStaleTimer() { + std::lock_guard guard(mStaleLock); + if (PowerHintMonitor::getInstance()->isRunning()) { + auto when = getStaleTime(); + auto now = std::chrono::steady_clock::now(); + mLastUpdatedTime.store(now); + if (now > when) { + mSession->updateUniveralBoostMode(); + } + if (!mIsMonitoringStale.load()) { + auto next = getStaleTime(); + PowerHintMonitor::getInstance()->getLooper()->sendMessageDelayed( + duration_cast(next - now).count(), this, NULL); + mIsMonitoringStale.store(true); + } + } +} + +time_point PowerHintSession::StaleHandler::getStaleTime() { + return mLastUpdatedTime.load() + + std::chrono::duration_cast(mSession->kAdpfRate) * sStaleTimeFactor; +} + +void PowerHintSession::StaleHandler::handleMessage(const Message &) { + std::lock_guard guard(mStaleLock); + auto now = std::chrono::steady_clock::now(); + auto when = getStaleTime(); + // Check if the session is stale based on the last_updated_time. + if (now > when) { + mSession->setStale(); + mIsMonitoringStale.store(false); + return; + } + // Schedule for the next checking time. + PowerHintMonitor::getInstance()->getLooper()->sendMessageDelayed( + duration_cast(when - now).count(), this, NULL); +} + +} // namespace pixel +} // namespace impl +} // namespace power +} // namespace hardware +} // namespace google +} // namespace aidl diff --git a/power-libperfmgr/aidl/PowerHintSession.h b/power-libperfmgr/aidl/PowerHintSession.h new file mode 100644 index 00000000..e3c0f849 --- /dev/null +++ b/power-libperfmgr/aidl/PowerHintSession.h @@ -0,0 +1,119 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +#include +#include + +namespace aidl { +namespace google { +namespace hardware { +namespace power { +namespace impl { +namespace pixel { + +using aidl::android::hardware::power::BnPowerHintSession; +using aidl::android::hardware::power::WorkDuration; +using ::android::Message; +using ::android::MessageHandler; +using ::android::sp; +using std::chrono::milliseconds; +using std::chrono::nanoseconds; +using std::chrono::steady_clock; +using std::chrono::time_point; + +static const int32_t kMaxUclampValue = 1024; +struct AppHintDesc { + AppHintDesc(int32_t tgid, int32_t uid, std::vector threadIds) + : tgid(tgid), + uid(uid), + threadIds(std::move(threadIds)), + duration(0LL), + current_min(0), + is_active(true), + update_count(0), + integral_error(0), + previous_error(0) {} + std::string toString() const; + const int32_t tgid; + const int32_t uid; + const std::vector threadIds; + nanoseconds duration; + int current_min; + // status + std::atomic is_active; + // pid + uint64_t update_count; + int64_t integral_error; + int64_t previous_error; +}; + +class PowerHintSession : public BnPowerHintSession { + public: + explicit PowerHintSession(int32_t tgid, int32_t uid, const std::vector &threadIds, + int64_t durationNanos, nanoseconds adpfRate); + ~PowerHintSession(); + ndk::ScopedAStatus close() override; + ndk::ScopedAStatus pause() override; + ndk::ScopedAStatus resume() override; + ndk::ScopedAStatus updateTargetWorkDuration(int64_t targetDurationNanos) override; + ndk::ScopedAStatus reportActualWorkDuration( + const std::vector &actualDurations) override; + bool isActive(); + bool isStale(); + const std::vector &getTidList() const; + + private: + class StaleHandler : public MessageHandler { + public: + StaleHandler(PowerHintSession *session) + : mSession(session), mIsMonitoringStale(false), mLastUpdatedTime(steady_clock::now()) {} + void handleMessage(const Message &message) override; + void updateStaleTimer(); + time_point getStaleTime(); + + private: + PowerHintSession *mSession; + std::atomic mIsMonitoringStale; + std::atomic> mLastUpdatedTime; + std::mutex mStaleLock; + }; + + private: + void setStale(); + void updateUniveralBoostMode(); + int setUclamp(int32_t min, int32_t max = kMaxUclampValue); + std::string getIdString() const; + AppHintDesc *mDescriptor = nullptr; + sp mStaleHandler; + sp mPowerManagerHandler; + std::mutex mLock; + const nanoseconds kAdpfRate; + std::atomic mSessionClosed = false; +}; + +} // namespace pixel +} // namespace impl +} // namespace power +} // namespace hardware +} // namespace google +} // namespace aidl diff --git a/power-libperfmgr/aidl/PowerSessionManager.cpp b/power-libperfmgr/aidl/PowerSessionManager.cpp new file mode 100644 index 00000000..fc73c01e --- /dev/null +++ b/power-libperfmgr/aidl/PowerSessionManager.cpp @@ -0,0 +1,163 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "powerhal-libperfmgr" +#define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL) + +#include +#include +#include + +#include "PowerSessionManager.h" + +namespace aidl { +namespace google { +namespace hardware { +namespace power { +namespace impl { +namespace pixel { + +void PowerSessionManager::setHintManager(std::shared_ptr const &hint_manager) { + // Only initialize hintmanager instance if hint is supported. + if (hint_manager->IsHintSupported(kDisableBoostHintName)) { + mHintManager = hint_manager; + } +} + +void PowerSessionManager::updateHintMode(const std::string &mode, bool enabled) { + ALOGV("PowerSessionManager::updateHintMode: mode: %s, enabled: %d", mode.c_str(), enabled); + if (enabled && mode.compare(0, 8, "REFRESH_") == 0) { + if (mode.compare("REFRESH_120FPS") == 0) { + mDisplayRefreshRate = 120; + } else if (mode.compare("REFRESH_90FPS") == 0) { + mDisplayRefreshRate = 90; + } else if (mode.compare("REFRESH_60FPS") == 0) { + mDisplayRefreshRate = 60; + } + } +} + +int PowerSessionManager::getDisplayRefreshRate() { + return mDisplayRefreshRate; +} + +void PowerSessionManager::addPowerSession(PowerHintSession *session) { + std::lock_guard guard(mLock); + for (auto t : session->getTidList()) { + if (mTidRefCountMap.find(t) == mTidRefCountMap.end()) { + if (!SetTaskProfiles(t, {"ResetUclampGrp"})) { + ALOGW("Failed to set ResetUclampGrp task profile for tid:%d", t); + } else { + mTidRefCountMap[t] = 1; + } + continue; + } + if (mTidRefCountMap[t] <= 0) { + ALOGE("Error! Unexpected zero/negative RefCount:%d for tid:%d", mTidRefCountMap[t], t); + continue; + } + mTidRefCountMap[t]++; + } + mSessions.insert(session); +} + +void PowerSessionManager::removePowerSession(PowerHintSession *session) { + std::lock_guard guard(mLock); + for (auto t : session->getTidList()) { + if (mTidRefCountMap.find(t) == mTidRefCountMap.end()) { + ALOGE("Unexpected Error! Failed to look up tid:%d in TidRefCountMap", t); + continue; + } + mTidRefCountMap[t]--; + if (mTidRefCountMap[t] <= 0) { + if (!SetTaskProfiles(t, {"NoResetUclampGrp"})) { + ALOGW("Failed to set NoResetUclampGrp task profile for tid:%d", t); + } + mTidRefCountMap.erase(t); + } + } + mSessions.erase(session); +} + +std::optional PowerSessionManager::isAnySessionActive() { + std::lock_guard guard(mLock); + bool active = false; + for (PowerHintSession *s : mSessions) { + // session active and not stale is actually active. + if (s->isActive() && !s->isStale()) { + active = true; + break; + } + } + if (active == mActive) { + return std::nullopt; + } else { + mActive = active; + } + + return active; +} + +void PowerSessionManager::handleMessage(const Message &) { + auto active = isAnySessionActive(); + if (!active.has_value()) { + return; + } + if (active.value()) { + disableSystemTopAppBoost(); + } else { + enableSystemTopAppBoost(); + } +} + +void PowerSessionManager::enableSystemTopAppBoost() { + if (mHintManager) { + ALOGV("PowerSessionManager::enableSystemTopAppBoost!!"); + mHintManager->EndHint(kDisableBoostHintName); + } +} + +void PowerSessionManager::disableSystemTopAppBoost() { + if (mHintManager) { + ALOGV("PowerSessionManager::disableSystemTopAppBoost!!"); + mHintManager->DoHint(kDisableBoostHintName); + } +} + +// =========== PowerHintMonitor implementation start from here =========== +void PowerHintMonitor::start() { + if (!isRunning()) { + run("PowerHintMonitor", ::android::PRIORITY_HIGHEST); + } +} + +bool PowerHintMonitor::threadLoop() { + while (true) { + mLooper->pollOnce(-1); + } + return true; +} + +sp PowerHintMonitor::getLooper() { + return mLooper; +} + +} // namespace pixel +} // namespace impl +} // namespace power +} // namespace hardware +} // namespace google +} // namespace aidl diff --git a/power-libperfmgr/aidl/PowerSessionManager.h b/power-libperfmgr/aidl/PowerSessionManager.h new file mode 100644 index 00000000..4b7c36d9 --- /dev/null +++ b/power-libperfmgr/aidl/PowerSessionManager.h @@ -0,0 +1,108 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "PowerHintSession.h" + +#include +#include +#include + +#include +#include +#include + +namespace aidl { +namespace google { +namespace hardware { +namespace power { +namespace impl { +namespace pixel { + +using ::android::Looper; +using ::android::Message; +using ::android::MessageHandler; +using ::android::Thread; +using ::android::perfmgr::HintManager; + +constexpr char kPowerHalAdpfDisableTopAppBoost[] = "vendor.powerhal.adpf.disable.hint"; + +class PowerSessionManager : public MessageHandler { + public: + // current hint info + void updateHintMode(const std::string &mode, bool enabled); + int getDisplayRefreshRate(); + // monitoring session status + void addPowerSession(PowerHintSession *session); + void removePowerSession(PowerHintSession *session); + + void handleMessage(const Message &message) override; + void setHintManager(std::shared_ptr const &hint_manager); + + // Singleton + static sp getInstance() { + static sp instance = new PowerSessionManager(); + return instance; + } + + private: + std::optional isAnySessionActive(); + void disableSystemTopAppBoost(); + void enableSystemTopAppBoost(); + const std::string kDisableBoostHintName; + std::shared_ptr mHintManager; + std::unordered_set mSessions; // protected by mLock + std::unordered_map mTidRefCountMap; // protected by mLock + std::mutex mLock; + int mDisplayRefreshRate; + bool mActive; // protected by mLock + // Singleton + PowerSessionManager() + : kDisableBoostHintName(::android::base::GetProperty(kPowerHalAdpfDisableTopAppBoost, + "ADPF_DISABLE_TA_BOOST")), + mHintManager(nullptr), + mDisplayRefreshRate(60), + mActive(false) {} + PowerSessionManager(PowerSessionManager const &) = delete; + void operator=(PowerSessionManager const &) = delete; +}; + +class PowerHintMonitor : public Thread { + public: + void start(); + bool threadLoop() override; + sp getLooper(); + // Singleton + static sp getInstance() { + static sp instance = new PowerHintMonitor(); + return instance; + } + PowerHintMonitor(PowerHintMonitor const &) = delete; + void operator=(PowerHintMonitor const &) = delete; + + private: + sp mLooper; + // Singleton + PowerHintMonitor() : Thread(false), mLooper(new Looper(true)) {} +}; + +} // namespace pixel +} // namespace impl +} // namespace power +} // namespace hardware +} // namespace google +} // namespace aidl diff --git a/power-libperfmgr/aidl/android.hardware.power-service.xiaomi_sdm660.xml b/power-libperfmgr/aidl/android.hardware.power-service.xiaomi_sdm660.xml index caf6ea2d..9f56debd 100644 --- a/power-libperfmgr/aidl/android.hardware.power-service.xiaomi_sdm660.xml +++ b/power-libperfmgr/aidl/android.hardware.power-service.xiaomi_sdm660.xml @@ -1,6 +1,7 @@ android.hardware.power + 2 IPower/default diff --git a/power-libperfmgr/aidl/service.cpp b/power-libperfmgr/aidl/service.cpp index 2f3c305c..3148ffc1 100644 --- a/power-libperfmgr/aidl/service.cpp +++ b/power-libperfmgr/aidl/service.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_TAG "android.hardware.power-service.xiaomi_sdm660-libperfmgr" +#define LOG_TAG "powerhal-libperfmgr" #include @@ -25,21 +25,29 @@ #include "Power.h" #include "PowerExt.h" +#include "PowerSessionManager.h" using aidl::google::hardware::power::impl::pixel::Power; using aidl::google::hardware::power::impl::pixel::PowerExt; +using aidl::google::hardware::power::impl::pixel::PowerHintMonitor; +using aidl::google::hardware::power::impl::pixel::PowerSessionManager; using ::android::perfmgr::HintManager; -constexpr char kPowerHalConfigPath[] = "/vendor/etc/powerhint.json"; -constexpr char kPowerHalInitProp[] = "vendor.powerhal.init"; +constexpr std::string_view kPowerHalInitProp("vendor.powerhal.init"); +constexpr std::string_view kConfigProperty("vendor.powerhal.config"); +constexpr std::string_view kConfigDefaultFileName("powerhint.json"); int main() { - LOG(INFO) << "Xiaomi SDM660 Power HAL AIDL Service with Extension is starting."; + const std::string config_path = + "/vendor/etc/" + + android::base::GetProperty(kConfigProperty.data(), kConfigDefaultFileName.data()); + LOG(INFO) << "Pixel Power HAL AIDL Service with Extension is starting with config: " + << config_path; // Parse config but do not start the looper - std::shared_ptr hm = HintManager::GetFromJSON(kPowerHalConfigPath, false); + std::shared_ptr hm = HintManager::GetFromJSON(config_path, false); if (!hm) { - LOG(FATAL) << "Invalid config: " << kPowerHalConfigPath; + LOG(FATAL) << "Invalid config: " << config_path; } // single thread @@ -58,10 +66,15 @@ int main() { const std::string instance = std::string() + Power::descriptor + "/default"; binder_status_t status = AServiceManager_addService(pw->asBinder().get(), instance.c_str()); CHECK(status == STATUS_OK); - LOG(INFO) << "Xiaomi SDM660 Power HAL AIDL Service with Extension is started."; + LOG(INFO) << "Pixel Power HAL AIDL Service with Extension is started."; + + if (::android::base::GetIntProperty("vendor.powerhal.adpf.rate", -1) != -1) { + PowerHintMonitor::getInstance()->start(); + PowerSessionManager::getInstance()->setHintManager(hm); + } std::thread initThread([&]() { - ::android::base::WaitForProperty(kPowerHalInitProp, "1"); + ::android::base::WaitForProperty(kPowerHalInitProp.data(), "1"); hm->Start(); }); initThread.detach(); @@ -69,6 +82,6 @@ int main() { ABinderProcess_joinThreadPool(); // should not reach - LOG(ERROR) << "Xiaomi SDM660 Power HAL AIDL Service with Extension just died."; + LOG(ERROR) << "Pixel Power HAL AIDL Service with Extension just died."; return EXIT_FAILURE; } diff --git a/power-libperfmgr/disp-power/InteractionHandler.cpp b/power-libperfmgr/disp-power/InteractionHandler.cpp index d30fe403..f6cd0e9a 100644 --- a/power-libperfmgr/disp-power/InteractionHandler.cpp +++ b/power-libperfmgr/disp-power/InteractionHandler.cpp @@ -14,44 +14,62 @@ * limitations under the License. */ -#define LOG_TAG "android.hardware.power@-service.xiaomi_sdm660-libperfmgr" +#define LOG_TAG "powerhal-libperfmgr" #define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL) +#include +#include + #include #include #include #include #include + +#include #include #include -#include #include "InteractionHandler.h" #define MAX_LENGTH 64 #define MSINSEC 1000L -#define USINMS 1000000L +#define NSINMS 1000000L -static const std::vector fb_idle_patch = {"/sys/class/drm/card0/device/idle_state", - "/sys/class/graphics/fb0/idle_state"}; +namespace aidl { +namespace google { +namespace hardware { +namespace power { +namespace impl { +namespace pixel { -InteractionHandler::InteractionHandler(std::shared_ptr const &hint_manager) - : mState(INTERACTION_STATE_UNINITIALIZED), - mWaitMs(100), - mMinDurationMs(1400), - mMaxDurationMs(5650), - mDurationMs(0), - mHintManager(hint_manager) {} +namespace { -InteractionHandler::~InteractionHandler() { - Exit(); +static const bool kDisplayIdleSupport = + ::android::base::GetBoolProperty("vendor.powerhal.disp.idle_support", true); +static const std::array kDispIdlePath = {"/sys/class/drm/card0/device/idle_state", + "/sys/class/graphics/fb0/idle_state"}; +static const uint32_t kWaitMs = + ::android::base::GetUintProperty("vendor.powerhal.disp.idle_wait", /*default*/ 100U); +static const uint32_t kMinDurationMs = + ::android::base::GetUintProperty("vendor.powerhal.interaction.min", /*default*/ 1400U); +static const uint32_t kMaxDurationMs = + ::android::base::GetUintProperty("vendor.powerhal.interaction.max", /*default*/ 5650U); +static const uint32_t kDurationOffsetMs = + ::android::base::GetUintProperty("vendor.powerhal.interaction.offset", /*default*/ 650U); + +static size_t CalcTimespecDiffMs(struct timespec start, struct timespec end) { + size_t diff_in_ms = 0; + diff_in_ms += (end.tv_sec - start.tv_sec) * MSINSEC; + diff_in_ms += (end.tv_nsec - start.tv_nsec) / NSINMS; + return diff_in_ms; } -static int fb_idle_open(void) { +static int FbIdleOpen(void) { int fd; - for (auto &path : fb_idle_patch) { - fd = open(path.c_str(), O_RDONLY); + for (const auto &path : kDispIdlePath) { + fd = open(path, O_RDONLY); if (fd >= 0) return fd; } @@ -59,13 +77,24 @@ static int fb_idle_open(void) { return -1; } +} // namespace + +InteractionHandler::InteractionHandler(std::shared_ptr const &hint_manager) + : mState(INTERACTION_STATE_UNINITIALIZED), + mDurationMs(0), + mHintManager(hint_manager) {} + +InteractionHandler::~InteractionHandler() { + Exit(); +} + bool InteractionHandler::Init() { std::lock_guard lk(mLock); if (mState != INTERACTION_STATE_UNINITIALIZED) return true; - int fd = fb_idle_open(); + int fd = FbIdleOpen(); if (fd < 0) return false; mIdleFd = fd; @@ -115,30 +144,27 @@ void InteractionHandler::PerfRel() { ATRACE_INT("interaction_lock", 0); } -size_t InteractionHandler::CalcTimespecDiffMs(struct timespec start, struct timespec end) { - size_t diff_in_us = 0; - diff_in_us += (end.tv_sec - start.tv_sec) * MSINSEC; - diff_in_us += (end.tv_nsec - start.tv_nsec) / USINMS; - return diff_in_us; -} - void InteractionHandler::Acquire(int32_t duration) { ATRACE_CALL(); std::lock_guard lk(mLock); - if (mState == INTERACTION_STATE_UNINITIALIZED) { - ALOGW("%s: called while uninitialized", __func__); - return; - } - int inputDuration = duration + 650; + int inputDuration = duration + kDurationOffsetMs; int finalDuration; - if (inputDuration > mMaxDurationMs) - finalDuration = mMaxDurationMs; - else if (inputDuration > mMinDurationMs) + if (inputDuration > kMaxDurationMs) + finalDuration = kMaxDurationMs; + else if (inputDuration > kMinDurationMs) finalDuration = inputDuration; else - finalDuration = mMinDurationMs; + finalDuration = kMinDurationMs; + + // Fallback to do boost directly + // 1) override property is set OR + // 2) InteractionHandler not initialized + if (!kDisplayIdleSupport || mState == INTERACTION_STATE_UNINITIALIZED) { + mHintManager->DoHint("INTERACTION", std::chrono::milliseconds(finalDuration)); + return; + } struct timespec cur_timespec; clock_gettime(CLOCK_MONOTONIC, &cur_timespec); @@ -235,6 +261,7 @@ void InteractionHandler::WaitForIdle(int32_t wait_ms, int32_t timeout_ms) { } void InteractionHandler::Routine() { + pthread_setname_np(pthread_self(), "DispIdle"); std::unique_lock lk(mLock, std::defer_lock); while (true) { @@ -245,7 +272,14 @@ void InteractionHandler::Routine() { mState = INTERACTION_STATE_WAITING; lk.unlock(); - WaitForIdle(mWaitMs, mDurationMs); + WaitForIdle(kWaitMs, mDurationMs); Release(); } } + +} // namespace pixel +} // namespace impl +} // namespace power +} // namespace hardware +} // namespace google +} // namespace aidl diff --git a/power-libperfmgr/disp-power/InteractionHandler.h b/power-libperfmgr/disp-power/InteractionHandler.h index ba767f14..8ee63417 100644 --- a/power-libperfmgr/disp-power/InteractionHandler.h +++ b/power-libperfmgr/disp-power/InteractionHandler.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef POWER_LIBPERFMGR_INTERACTIONHANDLER_H_ -#define POWER_LIBPERFMGR_INTERACTIONHANDLER_H_ +#pragma once #include #include @@ -25,9 +24,16 @@ #include +namespace aidl { +namespace google { +namespace hardware { +namespace power { +namespace impl { +namespace pixel { + using ::android::perfmgr::HintManager; -enum interaction_state { +enum InteractionState { INTERACTION_STATE_UNINITIALIZED, INTERACTION_STATE_IDLE, INTERACTION_STATE_INTERACTION, @@ -51,24 +57,21 @@ class InteractionHandler { void PerfLock(); void PerfRel(); - size_t CalcTimespecDiffMs(struct timespec start, struct timespec end); - - enum interaction_state mState; + enum InteractionState mState; int mIdleFd; int mEventFd; - - int32_t mWaitMs; - int32_t mMinDurationMs; - int32_t mMaxDurationMs; int32_t mDurationMs; - struct timespec mLastTimespec; - std::unique_ptr mThread; std::mutex mLock; std::condition_variable mCond; std::shared_ptr mHintManager; }; -#endif // POWER_LIBPERFMGR_INTERACTIONHANDLER_H_ +} // namespace pixel +} // namespace impl +} // namespace power +} // namespace hardware +} // namespace google +} // namespace aidl