| Michael Wright | 1509a23 | 2018-06-21 02:50:34 +0100 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright 2018 The Android Open Source Project | 
|  | 3 | * | 
|  | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 5 | * you may not use this file except in compliance with the License. | 
|  | 6 | * You may obtain a copy of the License at | 
|  | 7 | * | 
|  | 8 | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 9 | * | 
|  | 10 | * Unless required by applicable law or agreed to in writing, software | 
|  | 11 | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 13 | * See the License for the specific language governing permissions and | 
|  | 14 | * limitations under the License. | 
|  | 15 | */ | 
|  | 16 |  | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 17 | //#define LOG_NDEBUG 0 | 
|  | 18 |  | 
| Michael Wright | 1509a23 | 2018-06-21 02:50:34 +0100 | [diff] [blame] | 19 | #undef LOG_TAG | 
|  | 20 | #define LOG_TAG "PowerAdvisor" | 
|  | 21 |  | 
| Matt Buckley | 06f299a | 2021-09-24 19:43:51 +0000 | [diff] [blame] | 22 | #include <unistd.h> | 
| Michael Wright | 1509a23 | 2018-06-21 02:50:34 +0100 | [diff] [blame] | 23 | #include <cinttypes> | 
| Matt Buckley | 06f299a | 2021-09-24 19:43:51 +0000 | [diff] [blame] | 24 | #include <cstdint> | 
|  | 25 | #include <optional> | 
| Michael Wright | 1509a23 | 2018-06-21 02:50:34 +0100 | [diff] [blame] | 26 |  | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 27 | #include <android-base/properties.h> | 
| Michael Wright | 1509a23 | 2018-06-21 02:50:34 +0100 | [diff] [blame] | 28 | #include <utils/Log.h> | 
|  | 29 | #include <utils/Mutex.h> | 
|  | 30 |  | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 31 | #include <android/hardware/power/1.3/IPower.h> | 
|  | 32 | #include <android/hardware/power/IPower.h> | 
| Matt Buckley | 06f299a | 2021-09-24 19:43:51 +0000 | [diff] [blame] | 33 | #include <android/hardware/power/IPowerHintSession.h> | 
|  | 34 | #include <android/hardware/power/WorkDuration.h> | 
|  | 35 |  | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 36 | #include <binder/IServiceManager.h> | 
|  | 37 |  | 
|  | 38 | #include "../SurfaceFlingerProperties.h" | 
|  | 39 |  | 
| Michael Wright | 1509a23 | 2018-06-21 02:50:34 +0100 | [diff] [blame] | 40 | #include "PowerAdvisor.h" | 
| Alec Mouri | dea1ac5 | 2021-06-23 18:12:18 -0700 | [diff] [blame] | 41 | #include "SurfaceFlinger.h" | 
| Michael Wright | 1509a23 | 2018-06-21 02:50:34 +0100 | [diff] [blame] | 42 |  | 
|  | 43 | namespace android { | 
|  | 44 | namespace Hwc2 { | 
|  | 45 |  | 
|  | 46 | PowerAdvisor::~PowerAdvisor() = default; | 
|  | 47 |  | 
|  | 48 | namespace impl { | 
|  | 49 |  | 
|  | 50 | namespace V1_0 = android::hardware::power::V1_0; | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 51 | namespace V1_3 = android::hardware::power::V1_3; | 
| Michael Wright | 1509a23 | 2018-06-21 02:50:34 +0100 | [diff] [blame] | 52 | using V1_3::PowerHint; | 
|  | 53 |  | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 54 | using android::hardware::power::Boost; | 
|  | 55 | using android::hardware::power::IPower; | 
| Matt Buckley | 06f299a | 2021-09-24 19:43:51 +0000 | [diff] [blame] | 56 | using android::hardware::power::IPowerHintSession; | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 57 | using android::hardware::power::Mode; | 
| Matt Buckley | 06f299a | 2021-09-24 19:43:51 +0000 | [diff] [blame] | 58 | using android::hardware::power::WorkDuration; | 
|  | 59 |  | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 60 | using scheduler::OneShotTimer; | 
|  | 61 |  | 
| Matt Buckley | 06f299a | 2021-09-24 19:43:51 +0000 | [diff] [blame] | 62 | class AidlPowerHalWrapper; | 
|  | 63 |  | 
| Michael Wright | 1509a23 | 2018-06-21 02:50:34 +0100 | [diff] [blame] | 64 | PowerAdvisor::~PowerAdvisor() = default; | 
|  | 65 |  | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 66 | namespace { | 
|  | 67 | int32_t getUpdateTimeout() { | 
|  | 68 | // Default to a timeout of 80ms if nothing else is specified | 
|  | 69 | static int32_t timeout = sysprop::display_update_imminent_timeout_ms(80); | 
|  | 70 | return timeout; | 
|  | 71 | } | 
|  | 72 |  | 
|  | 73 | } // namespace | 
|  | 74 |  | 
| Alec Mouri | dea1ac5 | 2021-06-23 18:12:18 -0700 | [diff] [blame] | 75 | PowerAdvisor::PowerAdvisor(SurfaceFlinger& flinger) | 
|  | 76 | : mFlinger(flinger), | 
|  | 77 | mUseScreenUpdateTimer(getUpdateTimeout() > 0), | 
|  | 78 | mScreenUpdateTimer( | 
| Ady Abraham | db3dfee | 2020-11-17 17:07:12 -0800 | [diff] [blame] | 79 | "UpdateImminentTimer", OneShotTimer::Interval(getUpdateTimeout()), | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 80 | /* resetCallback */ [this] { mSendUpdateImminent.store(false); }, | 
| Alec Mouri | dea1ac5 | 2021-06-23 18:12:18 -0700 | [diff] [blame] | 81 | /* timeoutCallback */ | 
|  | 82 | [this] { | 
|  | 83 | mSendUpdateImminent.store(true); | 
|  | 84 | mFlinger.disableExpensiveRendering(); | 
|  | 85 | }) {} | 
|  | 86 |  | 
|  | 87 | void PowerAdvisor::init() { | 
|  | 88 | // Defer starting the screen update timer until SurfaceFlinger finishes construction. | 
|  | 89 | if (mUseScreenUpdateTimer) { | 
|  | 90 | mScreenUpdateTimer.start(); | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 91 | } | 
|  | 92 | } | 
| Michael Wright | 1509a23 | 2018-06-21 02:50:34 +0100 | [diff] [blame] | 93 |  | 
| Dan Stoza | 29e7bdf | 2020-03-23 14:43:09 -0700 | [diff] [blame] | 94 | void PowerAdvisor::onBootFinished() { | 
|  | 95 | mBootFinished.store(true); | 
| Matt Buckley | 06f299a | 2021-09-24 19:43:51 +0000 | [diff] [blame] | 96 | { | 
|  | 97 | std::lock_guard lock(mPowerHalMutex); | 
|  | 98 | HalWrapper* halWrapper = getPowerHal(); | 
|  | 99 | if (halWrapper != nullptr && usePowerHintSession()) { | 
|  | 100 | mPowerHintSessionRunning = halWrapper->startPowerHintSession(); | 
|  | 101 | } | 
|  | 102 | } | 
| Dan Stoza | 29e7bdf | 2020-03-23 14:43:09 -0700 | [diff] [blame] | 103 | } | 
|  | 104 |  | 
| Peiyong Lin | 74ca2f4 | 2019-01-14 19:36:57 -0800 | [diff] [blame] | 105 | void PowerAdvisor::setExpensiveRenderingExpected(DisplayId displayId, bool expected) { | 
| Michael Wright | 1509a23 | 2018-06-21 02:50:34 +0100 | [diff] [blame] | 106 | if (expected) { | 
|  | 107 | mExpensiveDisplays.insert(displayId); | 
|  | 108 | } else { | 
|  | 109 | mExpensiveDisplays.erase(displayId); | 
|  | 110 | } | 
|  | 111 |  | 
| Michael Wright | 1509a23 | 2018-06-21 02:50:34 +0100 | [diff] [blame] | 112 | const bool expectsExpensiveRendering = !mExpensiveDisplays.empty(); | 
|  | 113 | if (mNotifiedExpensiveRendering != expectsExpensiveRendering) { | 
| Dan Stoza | 2095000 | 2020-06-18 14:56:58 -0700 | [diff] [blame] | 114 | std::lock_guard lock(mPowerHalMutex); | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 115 | HalWrapper* const halWrapper = getPowerHal(); | 
|  | 116 | if (halWrapper == nullptr) { | 
| Peiyong Lin | 8193497 | 2018-07-02 11:00:54 -0700 | [diff] [blame] | 117 | return; | 
|  | 118 | } | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 119 |  | 
|  | 120 | if (!halWrapper->setExpensiveRendering(expectsExpensiveRendering)) { | 
|  | 121 | // The HAL has become unavailable; attempt to reconnect later | 
| Michael Wright | 1509a23 | 2018-06-21 02:50:34 +0100 | [diff] [blame] | 122 | mReconnectPowerHal = true; | 
|  | 123 | return; | 
|  | 124 | } | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 125 |  | 
| Michael Wright | 1509a23 | 2018-06-21 02:50:34 +0100 | [diff] [blame] | 126 | mNotifiedExpensiveRendering = expectsExpensiveRendering; | 
|  | 127 | } | 
|  | 128 | } | 
|  | 129 |  | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 130 | void PowerAdvisor::notifyDisplayUpdateImminent() { | 
| Dan Stoza | 29e7bdf | 2020-03-23 14:43:09 -0700 | [diff] [blame] | 131 | // Only start sending this notification once the system has booted so we don't introduce an | 
|  | 132 | // early-boot dependency on Power HAL | 
|  | 133 | if (!mBootFinished.load()) { | 
|  | 134 | return; | 
|  | 135 | } | 
|  | 136 |  | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 137 | if (mSendUpdateImminent.load()) { | 
| Dan Stoza | 2095000 | 2020-06-18 14:56:58 -0700 | [diff] [blame] | 138 | std::lock_guard lock(mPowerHalMutex); | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 139 | HalWrapper* const halWrapper = getPowerHal(); | 
|  | 140 | if (halWrapper == nullptr) { | 
|  | 141 | return; | 
|  | 142 | } | 
|  | 143 |  | 
|  | 144 | if (!halWrapper->notifyDisplayUpdateImminent()) { | 
|  | 145 | // The HAL has become unavailable; attempt to reconnect later | 
|  | 146 | mReconnectPowerHal = true; | 
|  | 147 | return; | 
|  | 148 | } | 
|  | 149 | } | 
|  | 150 |  | 
| Alec Mouri | dea1ac5 | 2021-06-23 18:12:18 -0700 | [diff] [blame] | 151 | if (mUseScreenUpdateTimer) { | 
|  | 152 | mScreenUpdateTimer.reset(); | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 153 | } | 
|  | 154 | } | 
|  | 155 |  | 
| Matt Buckley | 06f299a | 2021-09-24 19:43:51 +0000 | [diff] [blame] | 156 | // checks both if it supports and if it's enabled | 
|  | 157 | bool PowerAdvisor::usePowerHintSession() { | 
|  | 158 | // uses cached value since the underlying support and flag are unlikely to change at runtime | 
|  | 159 | ALOGE_IF(!mPowerHintEnabled.has_value(), "Power hint session cannot be used before boot!"); | 
|  | 160 | return mPowerHintEnabled.value_or(false) && supportsPowerHintSession(); | 
|  | 161 | } | 
|  | 162 |  | 
|  | 163 | bool PowerAdvisor::supportsPowerHintSession() { | 
|  | 164 | // cache to avoid needing lock every time | 
|  | 165 | if (!mSupportsPowerHint.has_value()) { | 
|  | 166 | std::lock_guard lock(mPowerHalMutex); | 
|  | 167 | HalWrapper* const halWrapper = getPowerHal(); | 
|  | 168 | mSupportsPowerHint = halWrapper->supportsPowerHintSession(); | 
|  | 169 | } | 
|  | 170 | return *mSupportsPowerHint; | 
|  | 171 | } | 
|  | 172 |  | 
|  | 173 | bool PowerAdvisor::isPowerHintSessionRunning() { | 
|  | 174 | return mPowerHintSessionRunning; | 
|  | 175 | } | 
|  | 176 |  | 
|  | 177 | void PowerAdvisor::setTargetWorkDuration(int64_t targetDurationNanos) { | 
|  | 178 | // we check "supports" here not "usePowerHintSession" because this needs to work | 
|  | 179 | // before the session is actually running, and "use" will always fail before boot | 
|  | 180 | // we store the values passed in before boot to start the session with during onBootFinished | 
|  | 181 | if (!supportsPowerHintSession()) { | 
|  | 182 | ALOGV("Power hint session target duration cannot be set, skipping"); | 
|  | 183 | return; | 
|  | 184 | } | 
|  | 185 | { | 
|  | 186 | std::lock_guard lock(mPowerHalMutex); | 
|  | 187 | HalWrapper* const halWrapper = getPowerHal(); | 
|  | 188 | if (halWrapper != nullptr) { | 
|  | 189 | halWrapper->setTargetWorkDuration(targetDurationNanos); | 
|  | 190 | } | 
|  | 191 | } | 
|  | 192 | } | 
|  | 193 |  | 
|  | 194 | void PowerAdvisor::setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) { | 
|  | 195 | // we check "supports" here not "usePowerHintSession" because this needs to wsork | 
|  | 196 | // before the session is actually running, and "use" will always fail before boot. | 
|  | 197 | // we store the values passed in before boot to start the session with during onBootFinished | 
|  | 198 | if (!supportsPowerHintSession()) { | 
|  | 199 | ALOGV("Power hint session thread ids cannot be set, skipping"); | 
|  | 200 | return; | 
|  | 201 | } | 
|  | 202 | { | 
|  | 203 | std::lock_guard lock(mPowerHalMutex); | 
|  | 204 | HalWrapper* const halWrapper = getPowerHal(); | 
|  | 205 | if (halWrapper != nullptr) { | 
|  | 206 | halWrapper->setPowerHintSessionThreadIds(const_cast<std::vector<int32_t>&>(threadIds)); | 
|  | 207 | } | 
|  | 208 | } | 
|  | 209 | } | 
|  | 210 |  | 
|  | 211 | void PowerAdvisor::sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timeStampNanos) { | 
|  | 212 | if (!mBootFinished || !usePowerHintSession()) { | 
|  | 213 | ALOGV("Actual work duration power hint cannot be sent, skipping"); | 
|  | 214 | return; | 
|  | 215 | } | 
|  | 216 | { | 
|  | 217 | std::lock_guard lock(mPowerHalMutex); | 
|  | 218 | HalWrapper* const halWrapper = getPowerHal(); | 
|  | 219 | if (halWrapper != nullptr) { | 
|  | 220 | halWrapper->sendActualWorkDuration(actualDurationNanos, timeStampNanos); | 
|  | 221 | } | 
|  | 222 | } | 
|  | 223 | } | 
|  | 224 |  | 
|  | 225 | // needs to be set after the flag is known but before PowerAdvisor enters onBootFinished | 
|  | 226 | void PowerAdvisor::enablePowerHint(bool enabled) { | 
|  | 227 | mPowerHintEnabled = enabled; | 
|  | 228 | } | 
|  | 229 |  | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 230 | class HidlPowerHalWrapper : public PowerAdvisor::HalWrapper { | 
|  | 231 | public: | 
|  | 232 | HidlPowerHalWrapper(sp<V1_3::IPower> powerHal) : mPowerHal(std::move(powerHal)) {} | 
|  | 233 |  | 
|  | 234 | ~HidlPowerHalWrapper() override = default; | 
|  | 235 |  | 
|  | 236 | static std::unique_ptr<HalWrapper> connect() { | 
|  | 237 | // Power HAL 1.3 is not guaranteed to be available, thus we need to query | 
|  | 238 | // Power HAL 1.0 first and try to cast it to Power HAL 1.3. | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 239 | sp<V1_3::IPower> powerHal = nullptr; | 
| Dan Stoza | 9c051c0 | 2020-02-28 10:19:07 -0800 | [diff] [blame] | 240 | sp<V1_0::IPower> powerHal_1_0 = V1_0::IPower::getService(); | 
|  | 241 | if (powerHal_1_0 != nullptr) { | 
|  | 242 | // Try to cast to Power HAL 1.3 | 
|  | 243 | powerHal = V1_3::IPower::castFrom(powerHal_1_0); | 
|  | 244 | if (powerHal == nullptr) { | 
|  | 245 | ALOGW("No Power HAL 1.3 service in system, disabling PowerAdvisor"); | 
|  | 246 | } else { | 
|  | 247 | ALOGI("Loaded Power HAL 1.3 service"); | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 248 | } | 
| Dan Stoza | 9c051c0 | 2020-02-28 10:19:07 -0800 | [diff] [blame] | 249 | } else { | 
|  | 250 | ALOGW("No Power HAL found, disabling PowerAdvisor"); | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 251 | } | 
| Dan Stoza | 9c051c0 | 2020-02-28 10:19:07 -0800 | [diff] [blame] | 252 |  | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 253 | if (powerHal == nullptr) { | 
|  | 254 | return nullptr; | 
|  | 255 | } | 
|  | 256 |  | 
|  | 257 | return std::make_unique<HidlPowerHalWrapper>(std::move(powerHal)); | 
|  | 258 | } | 
|  | 259 |  | 
|  | 260 | bool setExpensiveRendering(bool enabled) override { | 
|  | 261 | ALOGV("HIDL setExpensiveRendering %s", enabled ? "T" : "F"); | 
|  | 262 | auto ret = mPowerHal->powerHintAsync_1_3(PowerHint::EXPENSIVE_RENDERING, enabled); | 
|  | 263 | return ret.isOk(); | 
|  | 264 | } | 
|  | 265 |  | 
|  | 266 | bool notifyDisplayUpdateImminent() override { | 
|  | 267 | // Power HAL 1.x doesn't have a notification for this | 
|  | 268 | ALOGV("HIDL notifyUpdateImminent received but can't send"); | 
|  | 269 | return true; | 
|  | 270 | } | 
|  | 271 |  | 
| Matt Buckley | 06f299a | 2021-09-24 19:43:51 +0000 | [diff] [blame] | 272 | bool supportsPowerHintSession() override { return false; } | 
|  | 273 |  | 
|  | 274 | bool isPowerHintSessionRunning() override { return false; } | 
|  | 275 |  | 
|  | 276 | void restartPowerHintSession() override {} | 
|  | 277 |  | 
|  | 278 | void setPowerHintSessionThreadIds(const std::vector<int32_t>&) override {} | 
|  | 279 |  | 
|  | 280 | bool startPowerHintSession() override { return false; } | 
|  | 281 |  | 
|  | 282 | void setTargetWorkDuration(int64_t) override {} | 
|  | 283 |  | 
|  | 284 | void sendActualWorkDuration(int64_t, nsecs_t) override {} | 
|  | 285 |  | 
|  | 286 | bool shouldReconnectHAL() override { return false; } | 
|  | 287 |  | 
|  | 288 | std::vector<int32_t> getPowerHintSessionThreadIds() override { return std::vector<int32_t>{}; } | 
|  | 289 |  | 
|  | 290 | std::optional<int64_t> getTargetWorkDuration() override { return std::nullopt; } | 
|  | 291 |  | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 292 | private: | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 293 | const sp<V1_3::IPower> mPowerHal = nullptr; | 
|  | 294 | }; | 
|  | 295 |  | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 296 | class AidlPowerHalWrapper : public PowerAdvisor::HalWrapper { | 
|  | 297 | public: | 
|  | 298 | AidlPowerHalWrapper(sp<IPower> powerHal) : mPowerHal(std::move(powerHal)) { | 
|  | 299 | auto ret = mPowerHal->isModeSupported(Mode::EXPENSIVE_RENDERING, &mHasExpensiveRendering); | 
|  | 300 | if (!ret.isOk()) { | 
|  | 301 | mHasExpensiveRendering = false; | 
|  | 302 | } | 
|  | 303 |  | 
|  | 304 | ret = mPowerHal->isBoostSupported(Boost::DISPLAY_UPDATE_IMMINENT, | 
|  | 305 | &mHasDisplayUpdateImminent); | 
|  | 306 | if (!ret.isOk()) { | 
|  | 307 | mHasDisplayUpdateImminent = false; | 
|  | 308 | } | 
| Matt Buckley | 06f299a | 2021-09-24 19:43:51 +0000 | [diff] [blame] | 309 |  | 
|  | 310 | // This just gives a number not a binder status, so no .isOk() | 
|  | 311 | mSupportsPowerHints = mPowerHal->getInterfaceVersion() >= 2; | 
|  | 312 |  | 
|  | 313 | if (mSupportsPowerHints) { | 
|  | 314 | mPowerHintQueue.reserve(MAX_QUEUE_SIZE); | 
|  | 315 | } | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 316 | } | 
|  | 317 |  | 
| Matt Buckley | 06f299a | 2021-09-24 19:43:51 +0000 | [diff] [blame] | 318 | ~AidlPowerHalWrapper() override { | 
|  | 319 | if (mPowerHintSession != nullptr) { | 
|  | 320 | mPowerHintSession->close(); | 
|  | 321 | mPowerHintSession = nullptr; | 
|  | 322 | } | 
|  | 323 | }; | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 324 |  | 
|  | 325 | static std::unique_ptr<HalWrapper> connect() { | 
|  | 326 | // This only waits if the service is actually declared | 
|  | 327 | sp<IPower> powerHal = waitForVintfService<IPower>(); | 
|  | 328 | if (powerHal == nullptr) { | 
|  | 329 | return nullptr; | 
|  | 330 | } | 
|  | 331 | ALOGI("Loaded AIDL Power HAL service"); | 
|  | 332 |  | 
|  | 333 | return std::make_unique<AidlPowerHalWrapper>(std::move(powerHal)); | 
|  | 334 | } | 
|  | 335 |  | 
|  | 336 | bool setExpensiveRendering(bool enabled) override { | 
|  | 337 | ALOGV("AIDL setExpensiveRendering %s", enabled ? "T" : "F"); | 
|  | 338 | if (!mHasExpensiveRendering) { | 
|  | 339 | ALOGV("Skipped sending EXPENSIVE_RENDERING because HAL doesn't support it"); | 
|  | 340 | return true; | 
|  | 341 | } | 
|  | 342 |  | 
|  | 343 | auto ret = mPowerHal->setMode(Mode::EXPENSIVE_RENDERING, enabled); | 
|  | 344 | return ret.isOk(); | 
|  | 345 | } | 
|  | 346 |  | 
|  | 347 | bool notifyDisplayUpdateImminent() override { | 
|  | 348 | ALOGV("AIDL notifyDisplayUpdateImminent"); | 
|  | 349 | if (!mHasDisplayUpdateImminent) { | 
|  | 350 | ALOGV("Skipped sending DISPLAY_UPDATE_IMMINENT because HAL doesn't support it"); | 
|  | 351 | return true; | 
|  | 352 | } | 
|  | 353 |  | 
|  | 354 | auto ret = mPowerHal->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 0); | 
|  | 355 | return ret.isOk(); | 
|  | 356 | } | 
|  | 357 |  | 
| Matt Buckley | 06f299a | 2021-09-24 19:43:51 +0000 | [diff] [blame] | 358 | // only version 2+ of the aidl supports power hint sessions, hidl has no support | 
|  | 359 | bool supportsPowerHintSession() override { return mSupportsPowerHints; } | 
|  | 360 |  | 
|  | 361 | bool isPowerHintSessionRunning() override { return mPowerHintSession != nullptr; } | 
|  | 362 |  | 
|  | 363 | void closePowerHintSession() { | 
|  | 364 | if (mPowerHintSession != nullptr) { | 
|  | 365 | mPowerHintSession->close(); | 
|  | 366 | mPowerHintSession = nullptr; | 
|  | 367 | } | 
|  | 368 | } | 
|  | 369 |  | 
|  | 370 | void restartPowerHintSession() { | 
|  | 371 | closePowerHintSession(); | 
|  | 372 | startPowerHintSession(); | 
|  | 373 | } | 
|  | 374 |  | 
|  | 375 | void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) override { | 
|  | 376 | if (threadIds != mPowerHintThreadIds) { | 
|  | 377 | mPowerHintThreadIds = threadIds; | 
|  | 378 | if (isPowerHintSessionRunning()) { | 
|  | 379 | restartPowerHintSession(); | 
|  | 380 | } | 
|  | 381 | } | 
|  | 382 | } | 
|  | 383 |  | 
|  | 384 | bool startPowerHintSession() override { | 
|  | 385 | if (mPowerHintSession != nullptr || !mPowerHintTargetDuration.has_value() || | 
|  | 386 | mPowerHintThreadIds.empty()) { | 
|  | 387 | ALOGV("Cannot start power hint session, skipping"); | 
|  | 388 | return false; | 
|  | 389 | } | 
|  | 390 | auto ret = mPowerHal->createHintSession(getpid(), static_cast<int32_t>(getuid()), | 
|  | 391 | mPowerHintThreadIds, *mPowerHintTargetDuration, | 
|  | 392 | &mPowerHintSession); | 
|  | 393 | if (!ret.isOk()) { | 
|  | 394 | ALOGW("Failed to start power hint session with error: %s", | 
|  | 395 | ret.exceptionToString(ret.exceptionCode()).c_str()); | 
|  | 396 | // Indicate to the poweradvisor that this wrapper likely needs to be remade | 
|  | 397 | mShouldReconnectHal = true; | 
|  | 398 | } | 
|  | 399 | return isPowerHintSessionRunning(); | 
|  | 400 | } | 
|  | 401 |  | 
|  | 402 | bool shouldSetTargetDuration(int64_t targetDurationNanos) { | 
|  | 403 | if (!mLastTargetDurationSent.has_value()) { | 
|  | 404 | return true; | 
|  | 405 | } | 
|  | 406 |  | 
|  | 407 | // report if the change in target from our last submission to now exceeds the threshold | 
|  | 408 | return abs(1.0 - | 
|  | 409 | static_cast<double>(*mLastTargetDurationSent) / | 
|  | 410 | static_cast<double>(targetDurationNanos)) >= | 
|  | 411 | ALLOWED_TARGET_DEVIATION_PERCENT; | 
|  | 412 | } | 
|  | 413 |  | 
|  | 414 | void setTargetWorkDuration(int64_t targetDurationNanos) override { | 
|  | 415 | mPowerHintTargetDuration = targetDurationNanos; | 
|  | 416 | if (shouldSetTargetDuration(targetDurationNanos) && isPowerHintSessionRunning()) { | 
|  | 417 | mLastTargetDurationSent = targetDurationNanos; | 
|  | 418 | auto ret = mPowerHintSession->updateTargetWorkDuration(targetDurationNanos); | 
|  | 419 | if (!ret.isOk()) { | 
|  | 420 | ALOGW("Failed to set power hint target work duration with error: %s", | 
|  | 421 | ret.exceptionMessage().c_str()); | 
|  | 422 | mShouldReconnectHal = true; | 
|  | 423 | } | 
|  | 424 | } | 
|  | 425 | } | 
|  | 426 |  | 
|  | 427 | bool shouldReportActualDurationsNow() { | 
|  | 428 | // report if we have never reported before or have exceeded the max queue size | 
|  | 429 | if (!mLastMessageReported.has_value() || mPowerHintQueue.size() >= MAX_QUEUE_SIZE) { | 
|  | 430 | return true; | 
|  | 431 | } | 
|  | 432 |  | 
|  | 433 | // duration of most recent timing | 
|  | 434 | const double mostRecentActualDuration = | 
|  | 435 | static_cast<double>(mPowerHintQueue.back().durationNanos); | 
|  | 436 | // duration of the last timing actually reported to the powerhal | 
|  | 437 | const double lastReportedActualDuration = | 
|  | 438 | static_cast<double>(mLastMessageReported->durationNanos); | 
|  | 439 |  | 
|  | 440 | // report if the change in duration from then to now exceeds the threshold | 
|  | 441 | return abs(1.0 - mostRecentActualDuration / lastReportedActualDuration) >= | 
|  | 442 | ALLOWED_ACTUAL_DEVIATION_PERCENT; | 
|  | 443 | } | 
|  | 444 |  | 
|  | 445 | void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timeStampNanos) override { | 
|  | 446 | if (actualDurationNanos < 0 || !isPowerHintSessionRunning()) { | 
|  | 447 | ALOGV("Failed to send actual work duration, skipping"); | 
|  | 448 | return; | 
|  | 449 | } | 
|  | 450 |  | 
|  | 451 | WorkDuration duration; | 
|  | 452 | duration.durationNanos = actualDurationNanos; | 
|  | 453 | duration.timeStampNanos = timeStampNanos; | 
|  | 454 | mPowerHintQueue.push_back(duration); | 
|  | 455 |  | 
|  | 456 | // This rate limiter queues similar duration reports to the powerhal into | 
|  | 457 | // batches to avoid excessive binder calls. The criteria to send a given batch | 
|  | 458 | // are outlined in shouldReportActualDurationsNow() | 
|  | 459 | if (shouldReportActualDurationsNow()) { | 
|  | 460 | auto ret = mPowerHintSession->reportActualWorkDuration(mPowerHintQueue); | 
|  | 461 | if (!ret.isOk()) { | 
|  | 462 | ALOGW("Failed to report actual work durations with error: %s", | 
|  | 463 | ret.exceptionMessage().c_str()); | 
|  | 464 | mShouldReconnectHal = true; | 
|  | 465 | } | 
|  | 466 | mPowerHintQueue.clear(); | 
|  | 467 | mLastMessageReported = duration; | 
|  | 468 | } | 
|  | 469 | } | 
|  | 470 |  | 
|  | 471 | bool shouldReconnectHAL() override { return mShouldReconnectHal; } | 
|  | 472 |  | 
|  | 473 | std::vector<int32_t> getPowerHintSessionThreadIds() override { return mPowerHintThreadIds; } | 
|  | 474 |  | 
|  | 475 | std::optional<int64_t> getTargetWorkDuration() override { return mPowerHintTargetDuration; } | 
|  | 476 |  | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 477 | private: | 
| Matt Buckley | 06f299a | 2021-09-24 19:43:51 +0000 | [diff] [blame] | 478 | // max number of messages allowed in mPowerHintQueue before reporting is forced | 
|  | 479 | static constexpr int32_t MAX_QUEUE_SIZE = 15; | 
|  | 480 | // max percent the actual duration can vary without causing a report (eg: 0.1 = 10%) | 
|  | 481 | static constexpr double ALLOWED_ACTUAL_DEVIATION_PERCENT = 0.1; | 
|  | 482 | // max percent the target duration can vary without causing a report (eg: 0.05 = 5%) | 
|  | 483 | static constexpr double ALLOWED_TARGET_DEVIATION_PERCENT = 0.05; | 
|  | 484 |  | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 485 | const sp<IPower> mPowerHal = nullptr; | 
|  | 486 | bool mHasExpensiveRendering = false; | 
|  | 487 | bool mHasDisplayUpdateImminent = false; | 
| Matt Buckley | 06f299a | 2021-09-24 19:43:51 +0000 | [diff] [blame] | 488 | bool mShouldReconnectHal = false; // used to indicate an error state and need for reconstruction | 
|  | 489 | // This is not thread safe, but is currently protected by mPowerHalMutex so it needs no lock | 
|  | 490 | sp<IPowerHintSession> mPowerHintSession = nullptr; | 
|  | 491 | std::vector<WorkDuration> mPowerHintQueue; | 
|  | 492 | // halwrapper owns these values so we can init when we want and reconnect if broken | 
|  | 493 | std::optional<int64_t> mPowerHintTargetDuration; | 
|  | 494 | std::vector<int32_t> mPowerHintThreadIds; | 
|  | 495 | // keep track of the last messages sent for rate limiter change detection | 
|  | 496 | std::optional<WorkDuration> mLastMessageReported; | 
|  | 497 | std::optional<int64_t> mLastTargetDurationSent; | 
|  | 498 | bool mSupportsPowerHints; | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 499 | }; | 
|  | 500 |  | 
|  | 501 | PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() { | 
|  | 502 | static std::unique_ptr<HalWrapper> sHalWrapper = nullptr; | 
| Dan Stoza | 9c051c0 | 2020-02-28 10:19:07 -0800 | [diff] [blame] | 503 | static bool sHasHal = true; | 
| Michael Wright | 1509a23 | 2018-06-21 02:50:34 +0100 | [diff] [blame] | 504 |  | 
| Dan Stoza | 9c051c0 | 2020-02-28 10:19:07 -0800 | [diff] [blame] | 505 | if (!sHasHal) { | 
|  | 506 | return nullptr; | 
|  | 507 | } | 
|  | 508 |  | 
| Matt Buckley | 06f299a | 2021-09-24 19:43:51 +0000 | [diff] [blame] | 509 | // grab old hint session values before we destroy any existing wrapper | 
|  | 510 | std::vector<int32_t> oldPowerHintSessionThreadIds; | 
|  | 511 | std::optional<int64_t> oldTargetWorkDuration; | 
|  | 512 |  | 
|  | 513 | if (sHalWrapper != nullptr) { | 
|  | 514 | oldPowerHintSessionThreadIds = sHalWrapper->getPowerHintSessionThreadIds(); | 
|  | 515 | oldTargetWorkDuration = sHalWrapper->getTargetWorkDuration(); | 
|  | 516 | } | 
|  | 517 |  | 
| Dan Stoza | 9c051c0 | 2020-02-28 10:19:07 -0800 | [diff] [blame] | 518 | // If we used to have a HAL, but it stopped responding, attempt to reconnect | 
| Michael Wright | 1509a23 | 2018-06-21 02:50:34 +0100 | [diff] [blame] | 519 | if (mReconnectPowerHal) { | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 520 | sHalWrapper = nullptr; | 
| Michael Wright | 1509a23 | 2018-06-21 02:50:34 +0100 | [diff] [blame] | 521 | mReconnectPowerHal = false; | 
|  | 522 | } | 
|  | 523 |  | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 524 | if (sHalWrapper != nullptr) { | 
| Matt Buckley | 06f299a | 2021-09-24 19:43:51 +0000 | [diff] [blame] | 525 | auto wrapper = sHalWrapper.get(); | 
|  | 526 | // if the wrapper is fine, return it, but if it indicates a reconnect, remake it | 
|  | 527 | if (!wrapper->shouldReconnectHAL()) { | 
|  | 528 | return wrapper; | 
|  | 529 | } | 
|  | 530 | sHalWrapper = nullptr; | 
| Michael Wright | 1509a23 | 2018-06-21 02:50:34 +0100 | [diff] [blame] | 531 | } | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 532 |  | 
| Matt Buckley | 06f299a | 2021-09-24 19:43:51 +0000 | [diff] [blame] | 533 | // at this point, we know for sure there is no running session | 
|  | 534 | mPowerHintSessionRunning = false; | 
|  | 535 |  | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 536 | // First attempt to connect to the AIDL Power HAL | 
|  | 537 | sHalWrapper = AidlPowerHalWrapper::connect(); | 
|  | 538 |  | 
|  | 539 | // If that didn't succeed, attempt to connect to the HIDL Power HAL | 
|  | 540 | if (sHalWrapper == nullptr) { | 
|  | 541 | sHalWrapper = HidlPowerHalWrapper::connect(); | 
| Matt Buckley | 06f299a | 2021-09-24 19:43:51 +0000 | [diff] [blame] | 542 | } else { // if AIDL, pass on any existing hint session values | 
|  | 543 | // thread ids always safe to set | 
|  | 544 | sHalWrapper->setPowerHintSessionThreadIds(oldPowerHintSessionThreadIds); | 
|  | 545 | // only set duration and start if duration is defined | 
|  | 546 | if (oldTargetWorkDuration.has_value()) { | 
|  | 547 | sHalWrapper->setTargetWorkDuration(*oldTargetWorkDuration); | 
|  | 548 | // only start if possible to run and both threadids and duration are defined | 
|  | 549 | if (usePowerHintSession() && !oldPowerHintSessionThreadIds.empty()) { | 
|  | 550 | mPowerHintSessionRunning = sHalWrapper->startPowerHintSession(); | 
|  | 551 | } | 
|  | 552 | } | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 553 | } | 
|  | 554 |  | 
| Dan Stoza | 9c051c0 | 2020-02-28 10:19:07 -0800 | [diff] [blame] | 555 | // If we make it to this point and still don't have a HAL, it's unlikely we | 
|  | 556 | // will, so stop trying | 
|  | 557 | if (sHalWrapper == nullptr) { | 
|  | 558 | sHasHal = false; | 
|  | 559 | } | 
|  | 560 |  | 
| Dan Stoza | 030fbc1 | 2020-02-19 15:32:01 -0800 | [diff] [blame] | 561 | return sHalWrapper.get(); | 
| Michael Wright | 1509a23 | 2018-06-21 02:50:34 +0100 | [diff] [blame] | 562 | } | 
|  | 563 |  | 
|  | 564 | } // namespace impl | 
|  | 565 | } // namespace Hwc2 | 
|  | 566 | } // namespace android |