blob: 44c086d7d3fa736de62690205d332f58a1cb4511 [file] [log] [blame]
Michael Wright1509a232018-06-21 02:50:34 +01001/*
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 Stoza030fbc12020-02-19 15:32:01 -080017//#define LOG_NDEBUG 0
18
Ady Abrahamabce1652022-02-24 10:51:19 -080019#define ATRACE_TAG ATRACE_TAG_GRAPHICS
20
Michael Wright1509a232018-06-21 02:50:34 +010021#undef LOG_TAG
22#define LOG_TAG "PowerAdvisor"
23
Matt Buckley06f299a2021-09-24 19:43:51 +000024#include <unistd.h>
Michael Wright1509a232018-06-21 02:50:34 +010025#include <cinttypes>
Matt Buckley06f299a2021-09-24 19:43:51 +000026#include <cstdint>
27#include <optional>
Michael Wright1509a232018-06-21 02:50:34 +010028
Dan Stoza030fbc12020-02-19 15:32:01 -080029#include <android-base/properties.h>
Michael Wright1509a232018-06-21 02:50:34 +010030#include <utils/Log.h>
31#include <utils/Mutex.h>
Ady Abrahamabce1652022-02-24 10:51:19 -080032#include <utils/Trace.h>
Michael Wright1509a232018-06-21 02:50:34 +010033
Dan Stoza030fbc12020-02-19 15:32:01 -080034#include <android/hardware/power/1.3/IPower.h>
35#include <android/hardware/power/IPower.h>
Matt Buckley06f299a2021-09-24 19:43:51 +000036#include <android/hardware/power/IPowerHintSession.h>
37#include <android/hardware/power/WorkDuration.h>
38
Dan Stoza030fbc12020-02-19 15:32:01 -080039#include <binder/IServiceManager.h>
40
41#include "../SurfaceFlingerProperties.h"
42
Michael Wright1509a232018-06-21 02:50:34 +010043#include "PowerAdvisor.h"
Alec Mouridea1ac52021-06-23 18:12:18 -070044#include "SurfaceFlinger.h"
Michael Wright1509a232018-06-21 02:50:34 +010045
46namespace android {
47namespace Hwc2 {
48
49PowerAdvisor::~PowerAdvisor() = default;
50
51namespace impl {
52
53namespace V1_0 = android::hardware::power::V1_0;
Dan Stoza030fbc12020-02-19 15:32:01 -080054namespace V1_3 = android::hardware::power::V1_3;
Michael Wright1509a232018-06-21 02:50:34 +010055using V1_3::PowerHint;
56
Dan Stoza030fbc12020-02-19 15:32:01 -080057using android::hardware::power::Boost;
58using android::hardware::power::IPower;
Matt Buckley06f299a2021-09-24 19:43:51 +000059using android::hardware::power::IPowerHintSession;
Dan Stoza030fbc12020-02-19 15:32:01 -080060using android::hardware::power::Mode;
Matt Buckley06f299a2021-09-24 19:43:51 +000061using android::hardware::power::WorkDuration;
62
Dan Stoza030fbc12020-02-19 15:32:01 -080063using scheduler::OneShotTimer;
64
Matt Buckley06f299a2021-09-24 19:43:51 +000065class AidlPowerHalWrapper;
66
Michael Wright1509a232018-06-21 02:50:34 +010067PowerAdvisor::~PowerAdvisor() = default;
68
Dan Stoza030fbc12020-02-19 15:32:01 -080069namespace {
70int32_t getUpdateTimeout() {
71 // Default to a timeout of 80ms if nothing else is specified
72 static int32_t timeout = sysprop::display_update_imminent_timeout_ms(80);
73 return timeout;
74}
75
Ady Abrahamabce1652022-02-24 10:51:19 -080076void traceExpensiveRendering(bool enabled) {
77 if (enabled) {
78 ATRACE_ASYNC_BEGIN("ExpensiveRendering", 0);
79 } else {
80 ATRACE_ASYNC_END("ExpensiveRendering", 0);
81 }
82}
83
Dan Stoza030fbc12020-02-19 15:32:01 -080084} // namespace
85
Alec Mouridea1ac52021-06-23 18:12:18 -070086PowerAdvisor::PowerAdvisor(SurfaceFlinger& flinger)
87 : mFlinger(flinger),
88 mUseScreenUpdateTimer(getUpdateTimeout() > 0),
89 mScreenUpdateTimer(
Ady Abrahamdb3dfee2020-11-17 17:07:12 -080090 "UpdateImminentTimer", OneShotTimer::Interval(getUpdateTimeout()),
Dan Stoza030fbc12020-02-19 15:32:01 -080091 /* resetCallback */ [this] { mSendUpdateImminent.store(false); },
Alec Mouridea1ac52021-06-23 18:12:18 -070092 /* timeoutCallback */
93 [this] {
94 mSendUpdateImminent.store(true);
95 mFlinger.disableExpensiveRendering();
96 }) {}
97
98void PowerAdvisor::init() {
99 // Defer starting the screen update timer until SurfaceFlinger finishes construction.
100 if (mUseScreenUpdateTimer) {
101 mScreenUpdateTimer.start();
Dan Stoza030fbc12020-02-19 15:32:01 -0800102 }
103}
Michael Wright1509a232018-06-21 02:50:34 +0100104
Dan Stoza29e7bdf2020-03-23 14:43:09 -0700105void PowerAdvisor::onBootFinished() {
106 mBootFinished.store(true);
107}
108
Peiyong Lin74ca2f42019-01-14 19:36:57 -0800109void PowerAdvisor::setExpensiveRenderingExpected(DisplayId displayId, bool expected) {
Michael Wright1509a232018-06-21 02:50:34 +0100110 if (expected) {
111 mExpensiveDisplays.insert(displayId);
112 } else {
113 mExpensiveDisplays.erase(displayId);
114 }
115
Michael Wright1509a232018-06-21 02:50:34 +0100116 const bool expectsExpensiveRendering = !mExpensiveDisplays.empty();
117 if (mNotifiedExpensiveRendering != expectsExpensiveRendering) {
Dan Stoza20950002020-06-18 14:56:58 -0700118 std::lock_guard lock(mPowerHalMutex);
Dan Stoza030fbc12020-02-19 15:32:01 -0800119 HalWrapper* const halWrapper = getPowerHal();
120 if (halWrapper == nullptr) {
Peiyong Lin81934972018-07-02 11:00:54 -0700121 return;
122 }
Dan Stoza030fbc12020-02-19 15:32:01 -0800123
124 if (!halWrapper->setExpensiveRendering(expectsExpensiveRendering)) {
125 // The HAL has become unavailable; attempt to reconnect later
Michael Wright1509a232018-06-21 02:50:34 +0100126 mReconnectPowerHal = true;
127 return;
128 }
Dan Stoza030fbc12020-02-19 15:32:01 -0800129
Michael Wright1509a232018-06-21 02:50:34 +0100130 mNotifiedExpensiveRendering = expectsExpensiveRendering;
131 }
132}
133
Dan Stoza030fbc12020-02-19 15:32:01 -0800134void PowerAdvisor::notifyDisplayUpdateImminent() {
Dan Stoza29e7bdf2020-03-23 14:43:09 -0700135 // Only start sending this notification once the system has booted so we don't introduce an
136 // early-boot dependency on Power HAL
137 if (!mBootFinished.load()) {
138 return;
139 }
140
Dan Stoza030fbc12020-02-19 15:32:01 -0800141 if (mSendUpdateImminent.load()) {
Dan Stoza20950002020-06-18 14:56:58 -0700142 std::lock_guard lock(mPowerHalMutex);
Dan Stoza030fbc12020-02-19 15:32:01 -0800143 HalWrapper* const halWrapper = getPowerHal();
144 if (halWrapper == nullptr) {
145 return;
146 }
147
148 if (!halWrapper->notifyDisplayUpdateImminent()) {
149 // The HAL has become unavailable; attempt to reconnect later
150 mReconnectPowerHal = true;
151 return;
152 }
153 }
154
Alec Mouridea1ac52021-06-23 18:12:18 -0700155 if (mUseScreenUpdateTimer) {
156 mScreenUpdateTimer.reset();
Dan Stoza030fbc12020-02-19 15:32:01 -0800157 }
158}
159
Matt Buckley06f299a2021-09-24 19:43:51 +0000160// checks both if it supports and if it's enabled
161bool PowerAdvisor::usePowerHintSession() {
162 // uses cached value since the underlying support and flag are unlikely to change at runtime
Matt Buckley06f299a2021-09-24 19:43:51 +0000163 return mPowerHintEnabled.value_or(false) && supportsPowerHintSession();
164}
165
166bool PowerAdvisor::supportsPowerHintSession() {
167 // cache to avoid needing lock every time
168 if (!mSupportsPowerHint.has_value()) {
169 std::lock_guard lock(mPowerHalMutex);
170 HalWrapper* const halWrapper = getPowerHal();
171 mSupportsPowerHint = halWrapper->supportsPowerHintSession();
172 }
173 return *mSupportsPowerHint;
174}
175
176bool PowerAdvisor::isPowerHintSessionRunning() {
177 return mPowerHintSessionRunning;
178}
179
180void PowerAdvisor::setTargetWorkDuration(int64_t targetDurationNanos) {
Matt Buckleyef51fba2021-10-12 19:30:12 +0000181 if (!usePowerHintSession()) {
Matt Buckley06f299a2021-09-24 19:43:51 +0000182 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) {
Matt Buckleyef51fba2021-10-12 19:30:12 +0000189 halWrapper->setTargetWorkDuration(targetDurationNanos - kTargetSafetyMargin.count());
Matt Buckley06f299a2021-09-24 19:43:51 +0000190 }
191 }
192}
193
194void PowerAdvisor::sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timeStampNanos) {
195 if (!mBootFinished || !usePowerHintSession()) {
196 ALOGV("Actual work duration power hint cannot be sent, skipping");
197 return;
198 }
199 {
200 std::lock_guard lock(mPowerHalMutex);
201 HalWrapper* const halWrapper = getPowerHal();
202 if (halWrapper != nullptr) {
203 halWrapper->sendActualWorkDuration(actualDurationNanos, timeStampNanos);
204 }
205 }
206}
207
208// needs to be set after the flag is known but before PowerAdvisor enters onBootFinished
209void PowerAdvisor::enablePowerHint(bool enabled) {
210 mPowerHintEnabled = enabled;
211}
212
Matt Buckleyef51fba2021-10-12 19:30:12 +0000213bool PowerAdvisor::startPowerHintSession(const std::vector<int32_t>& threadIds) {
214 if (!usePowerHintSession()) {
215 ALOGI("Power hint session cannot be started, skipping");
216 }
217 {
218 std::lock_guard lock(mPowerHalMutex);
219 HalWrapper* halWrapper = getPowerHal();
220 if (halWrapper != nullptr && usePowerHintSession()) {
221 halWrapper->setPowerHintSessionThreadIds(threadIds);
222 mPowerHintSessionRunning = halWrapper->startPowerHintSession();
223 }
224 }
225 return mPowerHintSessionRunning;
226}
227
Dan Stoza030fbc12020-02-19 15:32:01 -0800228class HidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
229public:
230 HidlPowerHalWrapper(sp<V1_3::IPower> powerHal) : mPowerHal(std::move(powerHal)) {}
231
232 ~HidlPowerHalWrapper() override = default;
233
234 static std::unique_ptr<HalWrapper> connect() {
235 // Power HAL 1.3 is not guaranteed to be available, thus we need to query
236 // Power HAL 1.0 first and try to cast it to Power HAL 1.3.
Dan Stoza030fbc12020-02-19 15:32:01 -0800237 sp<V1_3::IPower> powerHal = nullptr;
Dan Stoza9c051c02020-02-28 10:19:07 -0800238 sp<V1_0::IPower> powerHal_1_0 = V1_0::IPower::getService();
239 if (powerHal_1_0 != nullptr) {
240 // Try to cast to Power HAL 1.3
241 powerHal = V1_3::IPower::castFrom(powerHal_1_0);
242 if (powerHal == nullptr) {
243 ALOGW("No Power HAL 1.3 service in system, disabling PowerAdvisor");
244 } else {
245 ALOGI("Loaded Power HAL 1.3 service");
Dan Stoza030fbc12020-02-19 15:32:01 -0800246 }
Dan Stoza9c051c02020-02-28 10:19:07 -0800247 } else {
248 ALOGW("No Power HAL found, disabling PowerAdvisor");
Dan Stoza030fbc12020-02-19 15:32:01 -0800249 }
Dan Stoza9c051c02020-02-28 10:19:07 -0800250
Dan Stoza030fbc12020-02-19 15:32:01 -0800251 if (powerHal == nullptr) {
252 return nullptr;
253 }
254
255 return std::make_unique<HidlPowerHalWrapper>(std::move(powerHal));
256 }
257
258 bool setExpensiveRendering(bool enabled) override {
259 ALOGV("HIDL setExpensiveRendering %s", enabled ? "T" : "F");
260 auto ret = mPowerHal->powerHintAsync_1_3(PowerHint::EXPENSIVE_RENDERING, enabled);
Ady Abrahamabce1652022-02-24 10:51:19 -0800261 if (ret.isOk()) {
262 traceExpensiveRendering(enabled);
263 }
Dan Stoza030fbc12020-02-19 15:32:01 -0800264 return ret.isOk();
265 }
266
267 bool notifyDisplayUpdateImminent() override {
268 // Power HAL 1.x doesn't have a notification for this
269 ALOGV("HIDL notifyUpdateImminent received but can't send");
270 return true;
271 }
272
Matt Buckley06f299a2021-09-24 19:43:51 +0000273 bool supportsPowerHintSession() override { return false; }
274
275 bool isPowerHintSessionRunning() override { return false; }
276
277 void restartPowerHintSession() override {}
278
279 void setPowerHintSessionThreadIds(const std::vector<int32_t>&) override {}
280
281 bool startPowerHintSession() override { return false; }
282
283 void setTargetWorkDuration(int64_t) override {}
284
285 void sendActualWorkDuration(int64_t, nsecs_t) override {}
286
287 bool shouldReconnectHAL() override { return false; }
288
289 std::vector<int32_t> getPowerHintSessionThreadIds() override { return std::vector<int32_t>{}; }
290
291 std::optional<int64_t> getTargetWorkDuration() override { return std::nullopt; }
292
Dan Stoza030fbc12020-02-19 15:32:01 -0800293private:
Dan Stoza030fbc12020-02-19 15:32:01 -0800294 const sp<V1_3::IPower> mPowerHal = nullptr;
295};
296
Dan Stoza030fbc12020-02-19 15:32:01 -0800297class AidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
298public:
299 AidlPowerHalWrapper(sp<IPower> powerHal) : mPowerHal(std::move(powerHal)) {
300 auto ret = mPowerHal->isModeSupported(Mode::EXPENSIVE_RENDERING, &mHasExpensiveRendering);
301 if (!ret.isOk()) {
302 mHasExpensiveRendering = false;
303 }
304
305 ret = mPowerHal->isBoostSupported(Boost::DISPLAY_UPDATE_IMMINENT,
306 &mHasDisplayUpdateImminent);
307 if (!ret.isOk()) {
308 mHasDisplayUpdateImminent = false;
309 }
Matt Buckley06f299a2021-09-24 19:43:51 +0000310
Matt Buckleyef51fba2021-10-12 19:30:12 +0000311 mSupportsPowerHint = checkPowerHintSessionSupported();
Dan Stoza030fbc12020-02-19 15:32:01 -0800312 }
313
Matt Buckley06f299a2021-09-24 19:43:51 +0000314 ~AidlPowerHalWrapper() override {
315 if (mPowerHintSession != nullptr) {
316 mPowerHintSession->close();
317 mPowerHintSession = nullptr;
318 }
319 };
Dan Stoza030fbc12020-02-19 15:32:01 -0800320
321 static std::unique_ptr<HalWrapper> connect() {
322 // This only waits if the service is actually declared
323 sp<IPower> powerHal = waitForVintfService<IPower>();
324 if (powerHal == nullptr) {
325 return nullptr;
326 }
327 ALOGI("Loaded AIDL Power HAL service");
328
329 return std::make_unique<AidlPowerHalWrapper>(std::move(powerHal));
330 }
331
332 bool setExpensiveRendering(bool enabled) override {
333 ALOGV("AIDL setExpensiveRendering %s", enabled ? "T" : "F");
334 if (!mHasExpensiveRendering) {
335 ALOGV("Skipped sending EXPENSIVE_RENDERING because HAL doesn't support it");
336 return true;
337 }
338
339 auto ret = mPowerHal->setMode(Mode::EXPENSIVE_RENDERING, enabled);
Ady Abrahamabce1652022-02-24 10:51:19 -0800340 if (ret.isOk()) {
341 traceExpensiveRendering(enabled);
342 }
Dan Stoza030fbc12020-02-19 15:32:01 -0800343 return ret.isOk();
344 }
345
346 bool notifyDisplayUpdateImminent() override {
347 ALOGV("AIDL notifyDisplayUpdateImminent");
348 if (!mHasDisplayUpdateImminent) {
349 ALOGV("Skipped sending DISPLAY_UPDATE_IMMINENT because HAL doesn't support it");
350 return true;
351 }
352
353 auto ret = mPowerHal->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 0);
354 return ret.isOk();
355 }
356
Matt Buckley06f299a2021-09-24 19:43:51 +0000357 // only version 2+ of the aidl supports power hint sessions, hidl has no support
Matt Buckleyef51fba2021-10-12 19:30:12 +0000358 bool supportsPowerHintSession() override { return mSupportsPowerHint; }
359
360 bool checkPowerHintSessionSupported() {
361 int64_t unused;
362 // Try to get preferred rate to determine if hint sessions are supported
363 // We check for isOk not EX_UNSUPPORTED_OPERATION to lump other errors
364 return mPowerHal->getHintSessionPreferredRate(&unused).isOk();
365 }
Matt Buckley06f299a2021-09-24 19:43:51 +0000366
367 bool isPowerHintSessionRunning() override { return mPowerHintSession != nullptr; }
368
369 void closePowerHintSession() {
370 if (mPowerHintSession != nullptr) {
371 mPowerHintSession->close();
372 mPowerHintSession = nullptr;
373 }
374 }
375
376 void restartPowerHintSession() {
377 closePowerHintSession();
378 startPowerHintSession();
379 }
380
381 void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) override {
382 if (threadIds != mPowerHintThreadIds) {
383 mPowerHintThreadIds = threadIds;
384 if (isPowerHintSessionRunning()) {
385 restartPowerHintSession();
386 }
387 }
388 }
389
390 bool startPowerHintSession() override {
Matt Buckleyef51fba2021-10-12 19:30:12 +0000391 if (mPowerHintSession != nullptr || mPowerHintThreadIds.empty()) {
Matt Buckley06f299a2021-09-24 19:43:51 +0000392 ALOGV("Cannot start power hint session, skipping");
393 return false;
394 }
395 auto ret = mPowerHal->createHintSession(getpid(), static_cast<int32_t>(getuid()),
Matt Buckleyef51fba2021-10-12 19:30:12 +0000396 mPowerHintThreadIds, mTargetDuration,
Matt Buckley06f299a2021-09-24 19:43:51 +0000397 &mPowerHintSession);
398 if (!ret.isOk()) {
399 ALOGW("Failed to start power hint session with error: %s",
400 ret.exceptionToString(ret.exceptionCode()).c_str());
Matt Buckleyef51fba2021-10-12 19:30:12 +0000401 } else {
402 mLastTargetDurationSent = mTargetDuration;
Matt Buckley06f299a2021-09-24 19:43:51 +0000403 }
404 return isPowerHintSessionRunning();
405 }
406
407 bool shouldSetTargetDuration(int64_t targetDurationNanos) {
Matt Buckley06f299a2021-09-24 19:43:51 +0000408 // report if the change in target from our last submission to now exceeds the threshold
409 return abs(1.0 -
Matt Buckleyef51fba2021-10-12 19:30:12 +0000410 static_cast<double>(mLastTargetDurationSent) /
Matt Buckley06f299a2021-09-24 19:43:51 +0000411 static_cast<double>(targetDurationNanos)) >=
Matt Buckleyef51fba2021-10-12 19:30:12 +0000412 kAllowedTargetDeviationPercent;
Matt Buckley06f299a2021-09-24 19:43:51 +0000413 }
414
415 void setTargetWorkDuration(int64_t targetDurationNanos) override {
Matt Buckleyef51fba2021-10-12 19:30:12 +0000416 ATRACE_CALL();
417 mTargetDuration = targetDurationNanos;
418 if (sTraceHintSessionData) ATRACE_INT64("Time target", targetDurationNanos);
419 if (!sNormalizeTarget && shouldSetTargetDuration(targetDurationNanos) &&
420 isPowerHintSessionRunning()) {
421 if (mLastActualDurationSent.has_value()) {
422 // update the error term here since we are actually sending an update to powerhal
423 if (sTraceHintSessionData)
424 ATRACE_INT64("Target error term",
425 targetDurationNanos - *mLastActualDurationSent);
426 }
427 ALOGV("Sending target time: %lld ns", static_cast<long long>(targetDurationNanos));
Matt Buckley06f299a2021-09-24 19:43:51 +0000428 mLastTargetDurationSent = targetDurationNanos;
429 auto ret = mPowerHintSession->updateTargetWorkDuration(targetDurationNanos);
430 if (!ret.isOk()) {
431 ALOGW("Failed to set power hint target work duration with error: %s",
432 ret.exceptionMessage().c_str());
433 mShouldReconnectHal = true;
434 }
435 }
436 }
437
438 bool shouldReportActualDurationsNow() {
Matt Buckley5793e162022-01-11 20:35:26 +0000439 // report if we have never reported before or are approaching a stale session
440 if (!mLastActualDurationSent.has_value() ||
441 (systemTime() - mLastActualReportTimestamp) > kStaleTimeout.count()) {
Matt Buckley06f299a2021-09-24 19:43:51 +0000442 return true;
443 }
444
Matt Buckleyef51fba2021-10-12 19:30:12 +0000445 if (!mActualDuration.has_value()) {
446 return false;
447 }
448
Matt Buckley06f299a2021-09-24 19:43:51 +0000449 // duration of most recent timing
Matt Buckleyef51fba2021-10-12 19:30:12 +0000450 const double mostRecentActualDuration = static_cast<double>(*mActualDuration);
Matt Buckley06f299a2021-09-24 19:43:51 +0000451 // duration of the last timing actually reported to the powerhal
Matt Buckleyef51fba2021-10-12 19:30:12 +0000452 const double lastReportedActualDuration = static_cast<double>(*mLastActualDurationSent);
Matt Buckley06f299a2021-09-24 19:43:51 +0000453
454 // report if the change in duration from then to now exceeds the threshold
455 return abs(1.0 - mostRecentActualDuration / lastReportedActualDuration) >=
Matt Buckleyef51fba2021-10-12 19:30:12 +0000456 kAllowedActualDeviationPercent;
Matt Buckley06f299a2021-09-24 19:43:51 +0000457 }
458
459 void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timeStampNanos) override {
Matt Buckleyef51fba2021-10-12 19:30:12 +0000460 ATRACE_CALL();
461
Matt Buckley06f299a2021-09-24 19:43:51 +0000462 if (actualDurationNanos < 0 || !isPowerHintSessionRunning()) {
463 ALOGV("Failed to send actual work duration, skipping");
464 return;
465 }
466
467 WorkDuration duration;
468 duration.durationNanos = actualDurationNanos;
Matt Buckleyef51fba2021-10-12 19:30:12 +0000469 mActualDuration = actualDurationNanos;
470
471 // normalize the sent values to a pre-set target
472 if (sNormalizeTarget) {
473 duration.durationNanos += mLastTargetDurationSent - mTargetDuration;
474 }
Matt Buckley06f299a2021-09-24 19:43:51 +0000475 duration.timeStampNanos = timeStampNanos;
476 mPowerHintQueue.push_back(duration);
477
Matt Buckleyef51fba2021-10-12 19:30:12 +0000478 long long targetNsec = mTargetDuration;
479 long long durationNsec = actualDurationNanos;
480
481 if (sTraceHintSessionData) {
482 ATRACE_INT64("Measured duration", durationNsec);
483 ATRACE_INT64("Target error term", targetNsec - durationNsec);
484 }
485
486 ALOGV("Sending actual work duration of: %lld on target: %lld with error: %lld",
487 durationNsec, targetNsec, targetNsec - durationNsec);
488
Matt Buckley06f299a2021-09-24 19:43:51 +0000489 // This rate limiter queues similar duration reports to the powerhal into
490 // batches to avoid excessive binder calls. The criteria to send a given batch
491 // are outlined in shouldReportActualDurationsNow()
492 if (shouldReportActualDurationsNow()) {
Matt Buckleyef51fba2021-10-12 19:30:12 +0000493 ALOGV("Sending hint update batch");
Matt Buckley5793e162022-01-11 20:35:26 +0000494 mLastActualReportTimestamp = systemTime();
Matt Buckley06f299a2021-09-24 19:43:51 +0000495 auto ret = mPowerHintSession->reportActualWorkDuration(mPowerHintQueue);
496 if (!ret.isOk()) {
497 ALOGW("Failed to report actual work durations with error: %s",
498 ret.exceptionMessage().c_str());
499 mShouldReconnectHal = true;
500 }
501 mPowerHintQueue.clear();
Matt Buckleyef51fba2021-10-12 19:30:12 +0000502 // we save the non-normalized value here to detect % changes
503 mLastActualDurationSent = actualDurationNanos;
Matt Buckley06f299a2021-09-24 19:43:51 +0000504 }
505 }
506
507 bool shouldReconnectHAL() override { return mShouldReconnectHal; }
508
509 std::vector<int32_t> getPowerHintSessionThreadIds() override { return mPowerHintThreadIds; }
510
Matt Buckleyef51fba2021-10-12 19:30:12 +0000511 std::optional<int64_t> getTargetWorkDuration() override { return mTargetDuration; }
Matt Buckley06f299a2021-09-24 19:43:51 +0000512
Dan Stoza030fbc12020-02-19 15:32:01 -0800513private:
514 const sp<IPower> mPowerHal = nullptr;
515 bool mHasExpensiveRendering = false;
516 bool mHasDisplayUpdateImminent = false;
Matt Buckleyef51fba2021-10-12 19:30:12 +0000517 // Used to indicate an error state and need for reconstruction
518 bool mShouldReconnectHal = false;
Matt Buckley06f299a2021-09-24 19:43:51 +0000519 // This is not thread safe, but is currently protected by mPowerHalMutex so it needs no lock
520 sp<IPowerHintSession> mPowerHintSession = nullptr;
Matt Buckleyef51fba2021-10-12 19:30:12 +0000521 // Queue of actual durations saved to report
Matt Buckley06f299a2021-09-24 19:43:51 +0000522 std::vector<WorkDuration> mPowerHintQueue;
Matt Buckleyef51fba2021-10-12 19:30:12 +0000523 // The latest un-normalized values we have received for target and actual
Matt Buckley5793e162022-01-11 20:35:26 +0000524 int64_t mTargetDuration = kDefaultTarget.count();
Matt Buckleyef51fba2021-10-12 19:30:12 +0000525 std::optional<int64_t> mActualDuration;
526 // The list of thread ids, stored so we can restart the session from this class if needed
Matt Buckley06f299a2021-09-24 19:43:51 +0000527 std::vector<int32_t> mPowerHintThreadIds;
Matt Buckleyef51fba2021-10-12 19:30:12 +0000528 bool mSupportsPowerHint;
529 // Keep track of the last messages sent for rate limiter change detection
530 std::optional<int64_t> mLastActualDurationSent;
Matt Buckley5793e162022-01-11 20:35:26 +0000531 // timestamp of the last report we sent, used to avoid stale sessions
532 int64_t mLastActualReportTimestamp = 0;
533 int64_t mLastTargetDurationSent = kDefaultTarget.count();
Matt Buckleyef51fba2021-10-12 19:30:12 +0000534 // Whether to normalize all the actual values as error terms relative to a constant target
535 // This saves a binder call by not setting the target, and should not affect the pid values
536 static const bool sNormalizeTarget;
537 // Whether we should emit ATRACE_INT data for hint sessions
538 static const bool sTraceHintSessionData;
Matt Buckleyef51fba2021-10-12 19:30:12 +0000539 // Max percent the actual duration can vary without causing a report (eg: 0.1 = 10%)
540 static constexpr double kAllowedActualDeviationPercent = 0.1;
541 // Max percent the target duration can vary without causing a report (eg: 0.05 = 5%)
542 static constexpr double kAllowedTargetDeviationPercent = 0.05;
543 // Target used for init and normalization, the actual value does not really matter
Matt Buckley5793e162022-01-11 20:35:26 +0000544 static constexpr const std::chrono::nanoseconds kDefaultTarget = 50ms;
Xiang Wang76236e12022-03-22 17:25:30 +0000545 // Amount of time after the last message was sent before the session goes stale
Matt Buckley5793e162022-01-11 20:35:26 +0000546 // actually 100ms but we use 80 here to ideally avoid going stale
547 static constexpr const std::chrono::nanoseconds kStaleTimeout = 80ms;
Dan Stoza030fbc12020-02-19 15:32:01 -0800548};
549
Matt Buckleyef51fba2021-10-12 19:30:12 +0000550const bool AidlPowerHalWrapper::sTraceHintSessionData =
551 base::GetBoolProperty(std::string("debug.sf.trace_hint_sessions"), false);
552
553const bool AidlPowerHalWrapper::sNormalizeTarget =
Xiang Wang76236e12022-03-22 17:25:30 +0000554 base::GetBoolProperty(std::string("debug.sf.normalize_hint_session_durations"), false);
Matt Buckleyef51fba2021-10-12 19:30:12 +0000555
Dan Stoza030fbc12020-02-19 15:32:01 -0800556PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() {
557 static std::unique_ptr<HalWrapper> sHalWrapper = nullptr;
Dan Stoza9c051c02020-02-28 10:19:07 -0800558 static bool sHasHal = true;
Michael Wright1509a232018-06-21 02:50:34 +0100559
Dan Stoza9c051c02020-02-28 10:19:07 -0800560 if (!sHasHal) {
561 return nullptr;
562 }
563
Matt Buckley06f299a2021-09-24 19:43:51 +0000564 // grab old hint session values before we destroy any existing wrapper
565 std::vector<int32_t> oldPowerHintSessionThreadIds;
566 std::optional<int64_t> oldTargetWorkDuration;
567
568 if (sHalWrapper != nullptr) {
569 oldPowerHintSessionThreadIds = sHalWrapper->getPowerHintSessionThreadIds();
570 oldTargetWorkDuration = sHalWrapper->getTargetWorkDuration();
571 }
572
Dan Stoza9c051c02020-02-28 10:19:07 -0800573 // If we used to have a HAL, but it stopped responding, attempt to reconnect
Michael Wright1509a232018-06-21 02:50:34 +0100574 if (mReconnectPowerHal) {
Dan Stoza030fbc12020-02-19 15:32:01 -0800575 sHalWrapper = nullptr;
Michael Wright1509a232018-06-21 02:50:34 +0100576 mReconnectPowerHal = false;
577 }
578
Dan Stoza030fbc12020-02-19 15:32:01 -0800579 if (sHalWrapper != nullptr) {
Matt Buckley06f299a2021-09-24 19:43:51 +0000580 auto wrapper = sHalWrapper.get();
581 // if the wrapper is fine, return it, but if it indicates a reconnect, remake it
582 if (!wrapper->shouldReconnectHAL()) {
583 return wrapper;
584 }
585 sHalWrapper = nullptr;
Michael Wright1509a232018-06-21 02:50:34 +0100586 }
Dan Stoza030fbc12020-02-19 15:32:01 -0800587
Matt Buckley06f299a2021-09-24 19:43:51 +0000588 // at this point, we know for sure there is no running session
589 mPowerHintSessionRunning = false;
590
Dan Stoza030fbc12020-02-19 15:32:01 -0800591 // First attempt to connect to the AIDL Power HAL
592 sHalWrapper = AidlPowerHalWrapper::connect();
593
594 // If that didn't succeed, attempt to connect to the HIDL Power HAL
595 if (sHalWrapper == nullptr) {
596 sHalWrapper = HidlPowerHalWrapper::connect();
Matt Buckley06f299a2021-09-24 19:43:51 +0000597 } else { // if AIDL, pass on any existing hint session values
598 // thread ids always safe to set
599 sHalWrapper->setPowerHintSessionThreadIds(oldPowerHintSessionThreadIds);
600 // only set duration and start if duration is defined
601 if (oldTargetWorkDuration.has_value()) {
602 sHalWrapper->setTargetWorkDuration(*oldTargetWorkDuration);
603 // only start if possible to run and both threadids and duration are defined
604 if (usePowerHintSession() && !oldPowerHintSessionThreadIds.empty()) {
605 mPowerHintSessionRunning = sHalWrapper->startPowerHintSession();
606 }
607 }
Dan Stoza030fbc12020-02-19 15:32:01 -0800608 }
609
Dan Stoza9c051c02020-02-28 10:19:07 -0800610 // If we make it to this point and still don't have a HAL, it's unlikely we
611 // will, so stop trying
612 if (sHalWrapper == nullptr) {
613 sHasHal = false;
614 }
615
Dan Stoza030fbc12020-02-19 15:32:01 -0800616 return sHalWrapper.get();
Michael Wright1509a232018-06-21 02:50:34 +0100617}
618
619} // namespace impl
620} // namespace Hwc2
621} // namespace android