blob: 1eb8ef35d0c9d1056fd166294f3d1f9ae4b6e86d [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>
Matt Buckley06f299a2021-09-24 19:43:51 +000035#include <android/hardware/power/IPowerHintSession.h>
36#include <android/hardware/power/WorkDuration.h>
37
Dan Stoza030fbc12020-02-19 15:32:01 -080038#include <binder/IServiceManager.h>
39
40#include "../SurfaceFlingerProperties.h"
41
Michael Wright1509a232018-06-21 02:50:34 +010042#include "PowerAdvisor.h"
Alec Mouridea1ac52021-06-23 18:12:18 -070043#include "SurfaceFlinger.h"
Michael Wright1509a232018-06-21 02:50:34 +010044
45namespace android {
46namespace Hwc2 {
47
48PowerAdvisor::~PowerAdvisor() = default;
49
50namespace impl {
51
52namespace V1_0 = android::hardware::power::V1_0;
Dan Stoza030fbc12020-02-19 15:32:01 -080053namespace V1_3 = android::hardware::power::V1_3;
Michael Wright1509a232018-06-21 02:50:34 +010054using V1_3::PowerHint;
55
Dan Stoza030fbc12020-02-19 15:32:01 -080056using android::hardware::power::Boost;
57using android::hardware::power::IPower;
Matt Buckley06f299a2021-09-24 19:43:51 +000058using android::hardware::power::IPowerHintSession;
Dan Stoza030fbc12020-02-19 15:32:01 -080059using android::hardware::power::Mode;
Matt Buckley06f299a2021-09-24 19:43:51 +000060using android::hardware::power::WorkDuration;
61
Dan Stoza030fbc12020-02-19 15:32:01 -080062using scheduler::OneShotTimer;
63
Michael Wright1509a232018-06-21 02:50:34 +010064PowerAdvisor::~PowerAdvisor() = default;
65
Dan Stoza030fbc12020-02-19 15:32:01 -080066namespace {
67int32_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
Ady Abrahamabce1652022-02-24 10:51:19 -080073void traceExpensiveRendering(bool enabled) {
74 if (enabled) {
75 ATRACE_ASYNC_BEGIN("ExpensiveRendering", 0);
76 } else {
77 ATRACE_ASYNC_END("ExpensiveRendering", 0);
78 }
79}
80
Dan Stoza030fbc12020-02-19 15:32:01 -080081} // namespace
82
Alec Mouric059dcf2022-05-05 23:40:07 +000083PowerAdvisor::PowerAdvisor(SurfaceFlinger& flinger) : mFlinger(flinger) {
84 if (getUpdateTimeout()) {
85 mScreenUpdateTimer.emplace("UpdateImminentTimer",
86 OneShotTimer::Interval(getUpdateTimeout()),
87 /* resetCallback */ nullptr,
88 /* timeoutCallback */
89 [this] {
90 const nsecs_t timeSinceLastUpdate =
91 systemTime() - mLastScreenUpdatedTime.load();
92 if (timeSinceLastUpdate < getUpdateTimeout()) {
93 // We may try to disable expensive rendering and allow
94 // for sending DISPLAY_UPDATE_IMMINENT hints too early if
95 // we idled very shortly after updating the screen, so
96 // make sure we wait enough time.
97 std::this_thread::sleep_for(std::chrono::nanoseconds(
98 getUpdateTimeout() - timeSinceLastUpdate));
99 }
100 mSendUpdateImminent.store(true);
101 mFlinger.disableExpensiveRendering();
102 });
103 }
104}
Alec Mouridea1ac52021-06-23 18:12:18 -0700105
106void PowerAdvisor::init() {
107 // Defer starting the screen update timer until SurfaceFlinger finishes construction.
Alec Mouric059dcf2022-05-05 23:40:07 +0000108 if (mScreenUpdateTimer) {
109 mScreenUpdateTimer->start();
Dan Stoza030fbc12020-02-19 15:32:01 -0800110 }
111}
Michael Wright1509a232018-06-21 02:50:34 +0100112
Dan Stoza29e7bdf2020-03-23 14:43:09 -0700113void PowerAdvisor::onBootFinished() {
114 mBootFinished.store(true);
115}
116
Peiyong Lin74ca2f42019-01-14 19:36:57 -0800117void PowerAdvisor::setExpensiveRenderingExpected(DisplayId displayId, bool expected) {
Michael Wright1509a232018-06-21 02:50:34 +0100118 if (expected) {
119 mExpensiveDisplays.insert(displayId);
120 } else {
121 mExpensiveDisplays.erase(displayId);
122 }
123
Michael Wright1509a232018-06-21 02:50:34 +0100124 const bool expectsExpensiveRendering = !mExpensiveDisplays.empty();
125 if (mNotifiedExpensiveRendering != expectsExpensiveRendering) {
Dan Stoza20950002020-06-18 14:56:58 -0700126 std::lock_guard lock(mPowerHalMutex);
Dan Stoza030fbc12020-02-19 15:32:01 -0800127 HalWrapper* const halWrapper = getPowerHal();
128 if (halWrapper == nullptr) {
Peiyong Lin81934972018-07-02 11:00:54 -0700129 return;
130 }
Dan Stoza030fbc12020-02-19 15:32:01 -0800131
132 if (!halWrapper->setExpensiveRendering(expectsExpensiveRendering)) {
133 // The HAL has become unavailable; attempt to reconnect later
Michael Wright1509a232018-06-21 02:50:34 +0100134 mReconnectPowerHal = true;
135 return;
136 }
Dan Stoza030fbc12020-02-19 15:32:01 -0800137
Michael Wright1509a232018-06-21 02:50:34 +0100138 mNotifiedExpensiveRendering = expectsExpensiveRendering;
139 }
140}
141
Dan Stoza030fbc12020-02-19 15:32:01 -0800142void PowerAdvisor::notifyDisplayUpdateImminent() {
Dan Stoza29e7bdf2020-03-23 14:43:09 -0700143 // Only start sending this notification once the system has booted so we don't introduce an
144 // early-boot dependency on Power HAL
145 if (!mBootFinished.load()) {
146 return;
147 }
148
Alec Mouric059dcf2022-05-05 23:40:07 +0000149 if (mSendUpdateImminent.exchange(false)) {
Dan Stoza20950002020-06-18 14:56:58 -0700150 std::lock_guard lock(mPowerHalMutex);
Dan Stoza030fbc12020-02-19 15:32:01 -0800151 HalWrapper* const halWrapper = getPowerHal();
152 if (halWrapper == nullptr) {
153 return;
154 }
155
156 if (!halWrapper->notifyDisplayUpdateImminent()) {
157 // The HAL has become unavailable; attempt to reconnect later
158 mReconnectPowerHal = true;
159 return;
160 }
Alec Mouric059dcf2022-05-05 23:40:07 +0000161
162 if (mScreenUpdateTimer) {
163 mScreenUpdateTimer->reset();
164 } else {
165 // If we don't have a screen update timer, then we don't throttle power hal calls so
166 // flip this bit back to allow for calling into power hal again.
167 mSendUpdateImminent.store(true);
168 }
Dan Stoza030fbc12020-02-19 15:32:01 -0800169 }
170
Alec Mouric059dcf2022-05-05 23:40:07 +0000171 if (mScreenUpdateTimer) {
172 mLastScreenUpdatedTime.store(systemTime());
Dan Stoza030fbc12020-02-19 15:32:01 -0800173 }
174}
175
Matt Buckley06f299a2021-09-24 19:43:51 +0000176// checks both if it supports and if it's enabled
177bool PowerAdvisor::usePowerHintSession() {
178 // uses cached value since the underlying support and flag are unlikely to change at runtime
Matt Buckley06f299a2021-09-24 19:43:51 +0000179 return mPowerHintEnabled.value_or(false) && supportsPowerHintSession();
180}
181
182bool PowerAdvisor::supportsPowerHintSession() {
183 // cache to avoid needing lock every time
184 if (!mSupportsPowerHint.has_value()) {
185 std::lock_guard lock(mPowerHalMutex);
186 HalWrapper* const halWrapper = getPowerHal();
187 mSupportsPowerHint = halWrapper->supportsPowerHintSession();
188 }
189 return *mSupportsPowerHint;
190}
191
192bool PowerAdvisor::isPowerHintSessionRunning() {
193 return mPowerHintSessionRunning;
194}
195
Matt Buckley50c44062022-01-17 20:48:10 +0000196void PowerAdvisor::setTargetWorkDuration(int64_t targetDuration) {
Matt Buckleyef51fba2021-10-12 19:30:12 +0000197 if (!usePowerHintSession()) {
Matt Buckley06f299a2021-09-24 19:43:51 +0000198 ALOGV("Power hint session target duration cannot be set, skipping");
199 return;
200 }
201 {
202 std::lock_guard lock(mPowerHalMutex);
203 HalWrapper* const halWrapper = getPowerHal();
204 if (halWrapper != nullptr) {
Matt Buckley50c44062022-01-17 20:48:10 +0000205 halWrapper->setTargetWorkDuration(targetDuration);
Matt Buckley06f299a2021-09-24 19:43:51 +0000206 }
207 }
208}
209
Matt Buckley50c44062022-01-17 20:48:10 +0000210void PowerAdvisor::sendActualWorkDuration() {
Matt Buckley06f299a2021-09-24 19:43:51 +0000211 if (!mBootFinished || !usePowerHintSession()) {
212 ALOGV("Actual work duration power hint cannot be sent, skipping");
213 return;
214 }
Matt Buckley50c44062022-01-17 20:48:10 +0000215 const std::optional<nsecs_t> actualDuration = estimateWorkDuration(false);
216 if (actualDuration.has_value()) {
Matt Buckley06f299a2021-09-24 19:43:51 +0000217 std::lock_guard lock(mPowerHalMutex);
218 HalWrapper* const halWrapper = getPowerHal();
219 if (halWrapper != nullptr) {
Matt Buckley50c44062022-01-17 20:48:10 +0000220 halWrapper->sendActualWorkDuration(*actualDuration + kTargetSafetyMargin.count(),
221 systemTime());
Matt Buckley06f299a2021-09-24 19:43:51 +0000222 }
223 }
224}
225
Matt Buckley50c44062022-01-17 20:48:10 +0000226void PowerAdvisor::sendPredictedWorkDuration() {
227 if (!mBootFinished || !usePowerHintSession()) {
228 ALOGV("Actual work duration power hint cannot be sent, skipping");
229 return;
230 }
231
232 const std::optional<nsecs_t> predictedDuration = estimateWorkDuration(true);
233
234 if (predictedDuration.has_value()) {
235 std::lock_guard lock(mPowerHalMutex);
236 HalWrapper* const halWrapper = getPowerHal();
237 if (halWrapper != nullptr) {
238 halWrapper->sendActualWorkDuration(*predictedDuration, systemTime());
239 }
240 }
241}
242
Matt Buckley06f299a2021-09-24 19:43:51 +0000243void PowerAdvisor::enablePowerHint(bool enabled) {
244 mPowerHintEnabled = enabled;
245}
246
Matt Buckleyef51fba2021-10-12 19:30:12 +0000247bool PowerAdvisor::startPowerHintSession(const std::vector<int32_t>& threadIds) {
248 if (!usePowerHintSession()) {
249 ALOGI("Power hint session cannot be started, skipping");
250 }
251 {
252 std::lock_guard lock(mPowerHalMutex);
253 HalWrapper* halWrapper = getPowerHal();
254 if (halWrapper != nullptr && usePowerHintSession()) {
255 halWrapper->setPowerHintSessionThreadIds(threadIds);
256 mPowerHintSessionRunning = halWrapper->startPowerHintSession();
257 }
258 }
259 return mPowerHintSessionRunning;
260}
261
Matt Buckley50c44062022-01-17 20:48:10 +0000262void PowerAdvisor::setGpuFenceTime(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime) {
263 DisplayTimingData& displayData = mDisplayTimingData[displayId];
264 if (displayData.gpuEndFenceTime) {
265 nsecs_t signalTime = displayData.gpuEndFenceTime->getSignalTime();
266 if (signalTime != Fence::SIGNAL_TIME_INVALID && signalTime != Fence::SIGNAL_TIME_PENDING) {
267 for (auto&& [_, otherDisplayData] : mDisplayTimingData) {
268 // If the previous display started before us but ended after we should have
269 // started, then it likely delayed our start time and we must compensate for that.
270 // Displays finishing earlier should have already made their way through this call
271 // and swapped their timing into "lastValid" from "latest", so we check that here.
272 if (!otherDisplayData.lastValidGpuStartTime.has_value()) continue;
273 if ((*otherDisplayData.lastValidGpuStartTime < *displayData.gpuStartTime) &&
274 (*otherDisplayData.lastValidGpuEndTime > *displayData.gpuStartTime)) {
275 displayData.lastValidGpuStartTime = *otherDisplayData.lastValidGpuEndTime;
276 break;
277 }
278 }
279 displayData.lastValidGpuStartTime = displayData.gpuStartTime;
280 displayData.lastValidGpuEndTime = signalTime;
281 }
282 }
283 displayData.gpuEndFenceTime = std::move(fenceTime);
284 displayData.gpuStartTime = systemTime();
285}
286
287void PowerAdvisor::setValidateTiming(DisplayId displayId, nsecs_t validateStartTime,
288 nsecs_t validateEndTime) {
289 DisplayTimingData& displayData = mDisplayTimingData[displayId];
290 displayData.validateStartTime = validateStartTime;
291 displayData.validateEndTime = validateEndTime;
292}
293
294void PowerAdvisor::setPresentTiming(DisplayId displayId, nsecs_t presentStartTime,
295 nsecs_t presentEndTime) {
296 DisplayTimingData& displayData = mDisplayTimingData[displayId];
297 displayData.presentStartTime = presentStartTime;
298 displayData.presentEndTime = presentEndTime;
299}
300
301void PowerAdvisor::setSkippedValidate(DisplayId displayId, bool skipped) {
302 mDisplayTimingData[displayId].skippedValidate = skipped;
303}
304
305void PowerAdvisor::setRequiresClientComposition(DisplayId displayId,
306 bool requiresClientComposition) {
307 mDisplayTimingData[displayId].usedClientComposition = requiresClientComposition;
308}
309
310void PowerAdvisor::setExpectedPresentTime(nsecs_t expectedPresentTime) {
311 mExpectedPresentTimes.append(expectedPresentTime);
312}
313
314void PowerAdvisor::setFrameDelay(nsecs_t frameDelayDuration) {
315 mFrameDelayDuration = frameDelayDuration;
316}
317
318void PowerAdvisor::setPresentDelayedTime(
319 DisplayId displayId, std::chrono::steady_clock::time_point earliestFrameStartTime) {
320 mDisplayTimingData[displayId].presentDelayedTime =
321 (earliestFrameStartTime - std::chrono::steady_clock::now()).count() + systemTime();
322}
323
324void PowerAdvisor::setCommitStart(nsecs_t commitStartTime) {
325 mCommitStartTimes.append(commitStartTime);
326}
327
328void PowerAdvisor::setCompositeEnd(nsecs_t compositeEnd) {
329 mLastCompositeEndTime = compositeEnd;
330 // calculate the postcomp time here as well
331 std::vector<DisplayId>&& displays = getOrderedDisplayIds(&DisplayTimingData::presentEndTime);
332 DisplayTimingData& timingData = mDisplayTimingData[displays.back()];
333 mLastPostcompDuration = compositeEnd -
334 (timingData.skippedValidate ? *timingData.validateEndTime : *timingData.presentEndTime);
335}
336
337void PowerAdvisor::setDisplays(std::vector<DisplayId>& displayIds) {
338 mDisplayIds = displayIds;
339}
340
341void PowerAdvisor::setTotalFrameTargetWorkDuration(nsecs_t targetDuration) {
342 mTotalFrameTargetDuration = targetDuration;
343}
344
345std::vector<DisplayId> PowerAdvisor::getOrderedDisplayIds(
346 std::optional<nsecs_t> DisplayTimingData::*sortBy) {
347 std::vector<DisplayId> sortedDisplays;
348 std::copy_if(mDisplayIds.begin(), mDisplayIds.end(), std::back_inserter(sortedDisplays),
349 [&](DisplayId id) {
350 return mDisplayTimingData.count(id) &&
351 (mDisplayTimingData[id].*sortBy).has_value();
352 });
353 std::sort(sortedDisplays.begin(), sortedDisplays.end(), [&](DisplayId idA, DisplayId idB) {
354 return *(mDisplayTimingData[idA].*sortBy) < *(mDisplayTimingData[idB].*sortBy);
355 });
356 return sortedDisplays;
357}
358
359std::optional<nsecs_t> PowerAdvisor::estimateWorkDuration(bool earlyHint) {
360 if (earlyHint && (!mExpectedPresentTimes.isFull() || !mCommitStartTimes.isFull())) {
361 return std::nullopt;
362 }
363
364 // Tracks when we finish presenting to hwc
365 nsecs_t estimatedEndTime = mCommitStartTimes[0];
366
367 // How long we spent this frame not doing anything, waiting for fences or vsync
368 nsecs_t idleDuration = 0;
369
370 // Most recent previous gpu end time in the current frame, probably from a prior display, used
371 // as the start time for the next gpu operation if it ran over time since it probably blocked
372 std::optional<nsecs_t> previousValidGpuEndTime;
373
374 // The currently estimated gpu end time for the frame,
375 // used to accumulate gpu time as we iterate over the active displays
376 std::optional<nsecs_t> estimatedGpuEndTime;
377
378 // If we're predicting at the start of the frame, we use last frame as our reference point
379 // If we're predicting at the end of the frame, we use the current frame as a reference point
380 nsecs_t referenceFrameStartTime = (earlyHint ? mCommitStartTimes[-1] : mCommitStartTimes[0]);
381
382 // We need an idea of when the last present fence fired and how long it made us wait
383 // If we're predicting at the start of the frame, we want frame n-2's present fence time
384 // If we're predicting at the end of the frame we want frame n-1's present time
385 nsecs_t referenceFenceTime =
386 (earlyHint ? mExpectedPresentTimes[-2] : mExpectedPresentTimes[-1]);
387 // The timing info for the previously calculated display, if there was one
388 std::optional<DisplayTimeline> previousDisplayReferenceTiming;
389 std::vector<DisplayId>&& displayIds =
390 getOrderedDisplayIds(&DisplayTimingData::presentStartTime);
391 DisplayTimeline referenceTiming, estimatedTiming;
392
393 // Iterate over the displays in the same order they are presented
394 for (DisplayId displayId : displayIds) {
395 if (mDisplayTimingData.count(displayId) == 0) {
396 continue;
397 }
398
399 auto& displayData = mDisplayTimingData.at(displayId);
400 referenceTiming = displayData.calculateDisplayTimeline(referenceFenceTime);
401
402 // If this is the first display, add the pre-present time to the total
403 if (!previousDisplayReferenceTiming.has_value()) {
404 estimatedEndTime += referenceTiming.prePresentTime - referenceFrameStartTime;
405 } else { // Otherwise add last display's postprocessing time to the total
406 estimatedEndTime += referenceTiming.prePresentTime -
407 previousDisplayReferenceTiming->postPresentTime;
408 }
409
410 estimatedTiming = referenceTiming.estimateTimelineFromReference(mExpectedPresentTimes[-1],
411 estimatedEndTime);
412 // Update predicted present finish time with this display's present time
413 estimatedEndTime = estimatedTiming.postPresentTime;
414
415 // Track how long we spent waiting for the fence, can be excluded from the timing estimate
416 idleDuration += estimatedTiming.probablyWaitsForFence
417 ? mExpectedPresentTimes[-1] - estimatedTiming.preFenceWaitTime
418 : 0;
419
420 // Track how long we spent waiting to present, can be excluded from the timing estimate
421 idleDuration +=
422 !earlyHint ? referenceTiming.presentStartTime - referenceTiming.prePresentTime : 0;
423
424 // Estimate the reference frame's gpu timing
425 auto gpuTiming = displayData.estimateGpuTiming(previousValidGpuEndTime);
426 if (gpuTiming.has_value()) {
427 previousValidGpuEndTime = gpuTiming->startTime + gpuTiming->duration;
428
429 // Estimate the prediction frame's gpu end time from the reference frame
430 estimatedGpuEndTime =
431 std::max(estimatedTiming.prePresentTime, estimatedGpuEndTime.value_or(0)) +
432 gpuTiming->duration;
433 }
434 previousDisplayReferenceTiming = referenceTiming;
435 }
436 ATRACE_INT64("Idle duration", idleDuration);
437
438 // Don't count time spent idly waiting in the estimate as we could do more work in that time
439 estimatedEndTime -= idleDuration;
440
441 // We finish the frame when both present and the gpu are done, so wait for the later of the two
442 // Also add the frame delay duration since the target did not move while we were delayed
443 nsecs_t totalDuration = mFrameDelayDuration +
444 std::max(estimatedEndTime, estimatedGpuEndTime.value_or(0)) - mCommitStartTimes[0];
445
446 // We finish SurfaceFlinger when post-composition finishes, so add that in here
447 nsecs_t flingerDuration = estimatedEndTime + mLastPostcompDuration - mCommitStartTimes[0];
448 nsecs_t combinedDuration = combineTimingEstimates(totalDuration, flingerDuration);
449
450 return std::make_optional(combinedDuration);
451}
452
453nsecs_t PowerAdvisor::combineTimingEstimates(nsecs_t totalDuration, nsecs_t flingerDuration) {
454 nsecs_t targetDuration;
455 {
456 std::lock_guard lock(mPowerHalMutex);
457 targetDuration = *getPowerHal()->getTargetWorkDuration();
458 }
459 if (!mTotalFrameTargetDuration.has_value()) return flingerDuration;
460
461 // Normalize total to the flinger target (vsync period) since that's how often we actually send
462 // hints
463 nsecs_t normalizedTotalDuration = (targetDuration * totalDuration) / *mTotalFrameTargetDuration;
464 return std::max(flingerDuration, normalizedTotalDuration);
465}
466
467PowerAdvisor::DisplayTimeline PowerAdvisor::DisplayTimeline::estimateTimelineFromReference(
468 nsecs_t fenceTime, nsecs_t displayStartTime) {
469 DisplayTimeline estimated;
470 estimated.prePresentTime = displayStartTime;
471
472 // We don't predict waiting for vsync alignment yet
473 estimated.presentStartTime = estimated.prePresentTime;
474
475 // For now just re-use last frame's post-present duration and assume it will not change much
476 // How long we expect to run before we start waiting for the fence
477 estimated.preFenceWaitTime = estimated.presentStartTime + (preFenceWaitTime - presentStartTime);
478 estimated.probablyWaitsForFence = fenceTime > estimated.preFenceWaitTime;
479 estimated.postPresentTime = postFenceDuration +
480 (estimated.probablyWaitsForFence ? fenceTime : estimated.preFenceWaitTime);
481 return estimated;
482}
483
484PowerAdvisor::DisplayTimeline PowerAdvisor::DisplayTimingData::calculateDisplayTimeline(
485 nsecs_t fenceTime) {
486 DisplayTimeline timeline;
487 // How long between calling present from flinger and trying to wait on the fence in HWC
488 const nsecs_t preFenceWaitDelay =
489 (skippedValidate ? kPrefenceDelaySkippedValidate : kPrefenceDelayValidated).count();
490
491 // Did our reference frame wait for an earliest present time before calling the HWC
492 const bool waitedOnPresentTime = presentDelayedTime.has_value() &&
493 *presentDelayedTime > *presentStartTime && *presentDelayedTime < *presentEndTime;
494
495 // Use validate start here if we skipped it because we did validate + present together
496 timeline.prePresentTime = skippedValidate ? *validateStartTime : *presentStartTime;
497
498 // Use validate end here if we skipped it because we did validate + present together
499 timeline.postPresentTime = skippedValidate ? *validateEndTime : *presentEndTime;
500
501 // When we think we started waiting for the fence after calling into present
502 // This is after any time spent waiting for the earliest present time
503 timeline.presentStartTime =
504 (waitedOnPresentTime ? *presentDelayedTime : timeline.prePresentTime);
505 timeline.preFenceWaitTime = timeline.presentStartTime + preFenceWaitDelay;
506 timeline.probablyWaitsForFence =
507 fenceTime > timeline.preFenceWaitTime && fenceTime < timeline.postPresentTime;
508
509 // How long we ran after we finished waiting for the fence but before present happened
510 timeline.postFenceDuration = timeline.postPresentTime -
511 (timeline.probablyWaitsForFence ? fenceTime : timeline.preFenceWaitTime);
512 return timeline;
513}
514
515std::optional<PowerAdvisor::GpuTimeline> PowerAdvisor::DisplayTimingData::estimateGpuTiming(
516 std::optional<nsecs_t> previousEnd) {
517 if (!(usedClientComposition && lastValidGpuStartTime.has_value() && gpuEndFenceTime)) {
518 return std::nullopt;
519 }
520 const nsecs_t latestGpuStartTime = std::max(previousEnd.value_or(0), *gpuStartTime);
521 const nsecs_t latestGpuEndTime = gpuEndFenceTime->getSignalTime();
522 nsecs_t gpuDuration = 0;
523 if (latestGpuEndTime != Fence::SIGNAL_TIME_INVALID &&
524 latestGpuEndTime != Fence::SIGNAL_TIME_PENDING) {
525 // If we know how long the most recent gpu duration was, use that
526 gpuDuration = latestGpuEndTime - latestGpuStartTime;
527 } else if (lastValidGpuEndTime.has_value()) {
528 // If we don't have the fence data, use the most recent information we do have
529 gpuDuration = *lastValidGpuEndTime - *lastValidGpuStartTime;
530 if (latestGpuEndTime == Fence::SIGNAL_TIME_PENDING) {
531 // If pending but went over the previous duration, use current time as the end
532 gpuDuration = std::max(gpuDuration, systemTime() - latestGpuStartTime);
533 }
534 }
535 return GpuTimeline{.duration = gpuDuration, .startTime = latestGpuStartTime};
536}
537
Dan Stoza030fbc12020-02-19 15:32:01 -0800538class HidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
539public:
540 HidlPowerHalWrapper(sp<V1_3::IPower> powerHal) : mPowerHal(std::move(powerHal)) {}
541
542 ~HidlPowerHalWrapper() override = default;
543
544 static std::unique_ptr<HalWrapper> connect() {
545 // Power HAL 1.3 is not guaranteed to be available, thus we need to query
546 // Power HAL 1.0 first and try to cast it to Power HAL 1.3.
Dan Stoza030fbc12020-02-19 15:32:01 -0800547 sp<V1_3::IPower> powerHal = nullptr;
Dan Stoza9c051c02020-02-28 10:19:07 -0800548 sp<V1_0::IPower> powerHal_1_0 = V1_0::IPower::getService();
549 if (powerHal_1_0 != nullptr) {
550 // Try to cast to Power HAL 1.3
551 powerHal = V1_3::IPower::castFrom(powerHal_1_0);
552 if (powerHal == nullptr) {
553 ALOGW("No Power HAL 1.3 service in system, disabling PowerAdvisor");
554 } else {
555 ALOGI("Loaded Power HAL 1.3 service");
Dan Stoza030fbc12020-02-19 15:32:01 -0800556 }
Dan Stoza9c051c02020-02-28 10:19:07 -0800557 } else {
558 ALOGW("No Power HAL found, disabling PowerAdvisor");
Dan Stoza030fbc12020-02-19 15:32:01 -0800559 }
Dan Stoza9c051c02020-02-28 10:19:07 -0800560
Dan Stoza030fbc12020-02-19 15:32:01 -0800561 if (powerHal == nullptr) {
562 return nullptr;
563 }
564
565 return std::make_unique<HidlPowerHalWrapper>(std::move(powerHal));
566 }
567
568 bool setExpensiveRendering(bool enabled) override {
569 ALOGV("HIDL setExpensiveRendering %s", enabled ? "T" : "F");
570 auto ret = mPowerHal->powerHintAsync_1_3(PowerHint::EXPENSIVE_RENDERING, enabled);
Ady Abrahamabce1652022-02-24 10:51:19 -0800571 if (ret.isOk()) {
572 traceExpensiveRendering(enabled);
573 }
Dan Stoza030fbc12020-02-19 15:32:01 -0800574 return ret.isOk();
575 }
576
577 bool notifyDisplayUpdateImminent() override {
578 // Power HAL 1.x doesn't have a notification for this
579 ALOGV("HIDL notifyUpdateImminent received but can't send");
580 return true;
581 }
582
Matt Buckley06f299a2021-09-24 19:43:51 +0000583 bool supportsPowerHintSession() override { return false; }
584
585 bool isPowerHintSessionRunning() override { return false; }
586
587 void restartPowerHintSession() override {}
588
589 void setPowerHintSessionThreadIds(const std::vector<int32_t>&) override {}
590
591 bool startPowerHintSession() override { return false; }
592
593 void setTargetWorkDuration(int64_t) override {}
594
595 void sendActualWorkDuration(int64_t, nsecs_t) override {}
596
597 bool shouldReconnectHAL() override { return false; }
598
599 std::vector<int32_t> getPowerHintSessionThreadIds() override { return std::vector<int32_t>{}; }
600
601 std::optional<int64_t> getTargetWorkDuration() override { return std::nullopt; }
602
Dan Stoza030fbc12020-02-19 15:32:01 -0800603private:
Dan Stoza030fbc12020-02-19 15:32:01 -0800604 const sp<V1_3::IPower> mPowerHal = nullptr;
605};
606
Xiang Wange12b4fa2022-03-25 23:48:40 +0000607AidlPowerHalWrapper::AidlPowerHalWrapper(sp<IPower> powerHal) : mPowerHal(std::move(powerHal)) {
608 auto ret = mPowerHal->isModeSupported(Mode::EXPENSIVE_RENDERING, &mHasExpensiveRendering);
609 if (!ret.isOk()) {
610 mHasExpensiveRendering = false;
Dan Stoza030fbc12020-02-19 15:32:01 -0800611 }
612
Xiang Wange12b4fa2022-03-25 23:48:40 +0000613 ret = mPowerHal->isBoostSupported(Boost::DISPLAY_UPDATE_IMMINENT, &mHasDisplayUpdateImminent);
614 if (!ret.isOk()) {
615 mHasDisplayUpdateImminent = false;
Dan Stoza030fbc12020-02-19 15:32:01 -0800616 }
617
Xiang Wange12b4fa2022-03-25 23:48:40 +0000618 mSupportsPowerHint = checkPowerHintSessionSupported();
Matt Buckley50c44062022-01-17 20:48:10 +0000619
620 mAllowedActualDeviation =
621 base::GetIntProperty<nsecs_t>("debug.sf.allowed_actual_deviation",
622 std::chrono::nanoseconds(250us).count());
Xiang Wange12b4fa2022-03-25 23:48:40 +0000623}
Dan Stoza030fbc12020-02-19 15:32:01 -0800624
Xiang Wange12b4fa2022-03-25 23:48:40 +0000625AidlPowerHalWrapper::~AidlPowerHalWrapper() {
626 if (mPowerHintSession != nullptr) {
627 mPowerHintSession->close();
628 mPowerHintSession = nullptr;
Dan Stoza030fbc12020-02-19 15:32:01 -0800629 }
Matt Buckley50c44062022-01-17 20:48:10 +0000630}
Dan Stoza030fbc12020-02-19 15:32:01 -0800631
Xiang Wange12b4fa2022-03-25 23:48:40 +0000632std::unique_ptr<PowerAdvisor::HalWrapper> AidlPowerHalWrapper::connect() {
633 // This only waits if the service is actually declared
634 sp<IPower> powerHal = waitForVintfService<IPower>();
635 if (powerHal == nullptr) {
636 return nullptr;
637 }
638 ALOGI("Loaded AIDL Power HAL service");
639
640 return std::make_unique<AidlPowerHalWrapper>(std::move(powerHal));
641}
642
643bool AidlPowerHalWrapper::setExpensiveRendering(bool enabled) {
644 ALOGV("AIDL setExpensiveRendering %s", enabled ? "T" : "F");
645 if (!mHasExpensiveRendering) {
646 ALOGV("Skipped sending EXPENSIVE_RENDERING because HAL doesn't support it");
647 return true;
648 }
649
650 auto ret = mPowerHal->setMode(Mode::EXPENSIVE_RENDERING, enabled);
651 if (ret.isOk()) {
652 traceExpensiveRendering(enabled);
653 }
654 return ret.isOk();
655}
656
657bool AidlPowerHalWrapper::notifyDisplayUpdateImminent() {
658 ALOGV("AIDL notifyDisplayUpdateImminent");
659 if (!mHasDisplayUpdateImminent) {
660 ALOGV("Skipped sending DISPLAY_UPDATE_IMMINENT because HAL doesn't support it");
661 return true;
662 }
663
664 auto ret = mPowerHal->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 0);
665 return ret.isOk();
666}
667
Matt Buckley50c44062022-01-17 20:48:10 +0000668// Only version 2+ of the aidl supports power hint sessions, hidl has no support
Xiang Wange12b4fa2022-03-25 23:48:40 +0000669bool AidlPowerHalWrapper::supportsPowerHintSession() {
670 return mSupportsPowerHint;
671}
672
673bool AidlPowerHalWrapper::checkPowerHintSessionSupported() {
674 int64_t unused;
675 // Try to get preferred rate to determine if hint sessions are supported
676 // We check for isOk not EX_UNSUPPORTED_OPERATION to lump together errors
677 return mPowerHal->getHintSessionPreferredRate(&unused).isOk();
678}
679
680bool AidlPowerHalWrapper::isPowerHintSessionRunning() {
681 return mPowerHintSession != nullptr;
682}
683
684void AidlPowerHalWrapper::closePowerHintSession() {
685 if (mPowerHintSession != nullptr) {
686 mPowerHintSession->close();
687 mPowerHintSession = nullptr;
688 }
689}
690
691void AidlPowerHalWrapper::restartPowerHintSession() {
692 closePowerHintSession();
693 startPowerHintSession();
694}
695
696void AidlPowerHalWrapper::setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) {
697 if (threadIds != mPowerHintThreadIds) {
698 mPowerHintThreadIds = threadIds;
699 if (isPowerHintSessionRunning()) {
700 restartPowerHintSession();
701 }
702 }
703}
704
705bool AidlPowerHalWrapper::startPowerHintSession() {
706 if (mPowerHintSession != nullptr || mPowerHintThreadIds.empty()) {
707 ALOGV("Cannot start power hint session, skipping");
708 return false;
709 }
710 auto ret =
711 mPowerHal->createHintSession(getpid(), static_cast<int32_t>(getuid()),
712 mPowerHintThreadIds, mTargetDuration, &mPowerHintSession);
713 if (!ret.isOk()) {
714 ALOGW("Failed to start power hint session with error: %s",
715 ret.exceptionToString(ret.exceptionCode()).c_str());
716 } else {
717 mLastTargetDurationSent = mTargetDuration;
718 }
719 return isPowerHintSessionRunning();
720}
721
Matt Buckley50c44062022-01-17 20:48:10 +0000722void AidlPowerHalWrapper::setTargetWorkDuration(int64_t targetDuration) {
Xiang Wange12b4fa2022-03-25 23:48:40 +0000723 ATRACE_CALL();
Matt Buckley50c44062022-01-17 20:48:10 +0000724 mTargetDuration = targetDuration;
725 if (sTraceHintSessionData) ATRACE_INT64("Time target", targetDuration);
726 if (isPowerHintSessionRunning() && (targetDuration != mLastTargetDurationSent)) {
727 ALOGV("Sending target time: %" PRId64 "ns", targetDuration);
728 mLastTargetDurationSent = targetDuration;
729 auto ret = mPowerHintSession->updateTargetWorkDuration(targetDuration);
Xiang Wange12b4fa2022-03-25 23:48:40 +0000730 if (!ret.isOk()) {
731 ALOGW("Failed to set power hint target work duration with error: %s",
732 ret.exceptionMessage().c_str());
733 mShouldReconnectHal = true;
734 }
735 }
736}
737
Matt Buckley50c44062022-01-17 20:48:10 +0000738bool AidlPowerHalWrapper::shouldReportActualDurations() {
739 // Report if we have never reported before or are approaching a stale session
Xiang Wange12b4fa2022-03-25 23:48:40 +0000740 if (!mLastActualDurationSent.has_value() ||
741 (systemTime() - mLastActualReportTimestamp) > kStaleTimeout.count()) {
742 return true;
743 }
744
745 if (!mActualDuration.has_value()) {
746 return false;
747 }
Matt Buckley50c44062022-01-17 20:48:10 +0000748 // Report if the change in actual duration exceeds the threshold
749 return abs(*mActualDuration - *mLastActualDurationSent) > mAllowedActualDeviation;
Xiang Wange12b4fa2022-03-25 23:48:40 +0000750}
751
Matt Buckley50c44062022-01-17 20:48:10 +0000752void AidlPowerHalWrapper::sendActualWorkDuration(int64_t actualDuration, nsecs_t timestamp) {
Xiang Wange12b4fa2022-03-25 23:48:40 +0000753 ATRACE_CALL();
754
Matt Buckley50c44062022-01-17 20:48:10 +0000755 if (actualDuration < 0 || !isPowerHintSessionRunning()) {
Xiang Wange12b4fa2022-03-25 23:48:40 +0000756 ALOGV("Failed to send actual work duration, skipping");
757 return;
758 }
Matt Buckley50c44062022-01-17 20:48:10 +0000759 const nsecs_t reportedDuration = actualDuration;
Xiang Wange12b4fa2022-03-25 23:48:40 +0000760
Xiang Wang0aba49e2022-04-06 16:13:59 +0000761 mActualDuration = reportedDuration;
762 WorkDuration duration;
763 duration.durationNanos = reportedDuration;
Matt Buckley50c44062022-01-17 20:48:10 +0000764 duration.timeStampNanos = timestamp;
Xiang Wange12b4fa2022-03-25 23:48:40 +0000765 mPowerHintQueue.push_back(duration);
766
Xiang Wange12b4fa2022-03-25 23:48:40 +0000767 if (sTraceHintSessionData) {
Matt Buckley50c44062022-01-17 20:48:10 +0000768 ATRACE_INT64("Measured duration", actualDuration);
769 ATRACE_INT64("Target error term", actualDuration - mTargetDuration);
Xiang Wang0aba49e2022-04-06 16:13:59 +0000770
771 ATRACE_INT64("Reported duration", reportedDuration);
772 ATRACE_INT64("Reported target", mLastTargetDurationSent);
Matt Buckley50c44062022-01-17 20:48:10 +0000773 ATRACE_INT64("Reported target error term", reportedDuration - mLastTargetDurationSent);
Xiang Wange12b4fa2022-03-25 23:48:40 +0000774 }
775
Xiang Wang0aba49e2022-04-06 16:13:59 +0000776 ALOGV("Sending actual work duration of: %" PRId64 " on reported target: %" PRId64
Xiang Wange12b4fa2022-03-25 23:48:40 +0000777 " with error: %" PRId64,
Matt Buckley50c44062022-01-17 20:48:10 +0000778 reportedDuration, mLastTargetDurationSent, reportedDuration - mLastTargetDurationSent);
Xiang Wange12b4fa2022-03-25 23:48:40 +0000779
780 // This rate limiter queues similar duration reports to the powerhal into
781 // batches to avoid excessive binder calls. The criteria to send a given batch
782 // are outlined in shouldReportActualDurationsNow()
Matt Buckley50c44062022-01-17 20:48:10 +0000783 if (shouldReportActualDurations()) {
Xiang Wange12b4fa2022-03-25 23:48:40 +0000784 ALOGV("Sending hint update batch");
785 mLastActualReportTimestamp = systemTime();
786 auto ret = mPowerHintSession->reportActualWorkDuration(mPowerHintQueue);
787 if (!ret.isOk()) {
788 ALOGW("Failed to report actual work durations with error: %s",
789 ret.exceptionMessage().c_str());
790 mShouldReconnectHal = true;
791 }
792 mPowerHintQueue.clear();
Matt Buckley50c44062022-01-17 20:48:10 +0000793 // We save the actual duration here for rate limiting
794 mLastActualDurationSent = actualDuration;
Xiang Wange12b4fa2022-03-25 23:48:40 +0000795 }
796}
797
798bool AidlPowerHalWrapper::shouldReconnectHAL() {
799 return mShouldReconnectHal;
800}
801
802std::vector<int32_t> AidlPowerHalWrapper::getPowerHintSessionThreadIds() {
803 return mPowerHintThreadIds;
804}
805
806std::optional<int64_t> AidlPowerHalWrapper::getTargetWorkDuration() {
807 return mTargetDuration;
808}
809
Matt Buckley50c44062022-01-17 20:48:10 +0000810void AidlPowerHalWrapper::setAllowedActualDeviation(nsecs_t allowedDeviation) {
811 mAllowedActualDeviation = allowedDeviation;
812}
813
Matt Buckleyef51fba2021-10-12 19:30:12 +0000814const bool AidlPowerHalWrapper::sTraceHintSessionData =
815 base::GetBoolProperty(std::string("debug.sf.trace_hint_sessions"), false);
816
Dan Stoza030fbc12020-02-19 15:32:01 -0800817PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() {
818 static std::unique_ptr<HalWrapper> sHalWrapper = nullptr;
Dan Stoza9c051c02020-02-28 10:19:07 -0800819 static bool sHasHal = true;
Michael Wright1509a232018-06-21 02:50:34 +0100820
Dan Stoza9c051c02020-02-28 10:19:07 -0800821 if (!sHasHal) {
822 return nullptr;
823 }
824
Matt Buckley50c44062022-01-17 20:48:10 +0000825 // Grab old hint session values before we destroy any existing wrapper
Matt Buckley06f299a2021-09-24 19:43:51 +0000826 std::vector<int32_t> oldPowerHintSessionThreadIds;
827 std::optional<int64_t> oldTargetWorkDuration;
828
829 if (sHalWrapper != nullptr) {
830 oldPowerHintSessionThreadIds = sHalWrapper->getPowerHintSessionThreadIds();
831 oldTargetWorkDuration = sHalWrapper->getTargetWorkDuration();
832 }
833
Dan Stoza9c051c02020-02-28 10:19:07 -0800834 // If we used to have a HAL, but it stopped responding, attempt to reconnect
Michael Wright1509a232018-06-21 02:50:34 +0100835 if (mReconnectPowerHal) {
Dan Stoza030fbc12020-02-19 15:32:01 -0800836 sHalWrapper = nullptr;
Michael Wright1509a232018-06-21 02:50:34 +0100837 mReconnectPowerHal = false;
838 }
839
Dan Stoza030fbc12020-02-19 15:32:01 -0800840 if (sHalWrapper != nullptr) {
Matt Buckley06f299a2021-09-24 19:43:51 +0000841 auto wrapper = sHalWrapper.get();
Matt Buckley50c44062022-01-17 20:48:10 +0000842 // If the wrapper is fine, return it, but if it indicates a reconnect, remake it
Matt Buckley06f299a2021-09-24 19:43:51 +0000843 if (!wrapper->shouldReconnectHAL()) {
844 return wrapper;
845 }
Xiang Wang65a2e6f2022-04-18 21:19:17 +0000846 ALOGD("Reconnecting Power HAL");
Matt Buckley06f299a2021-09-24 19:43:51 +0000847 sHalWrapper = nullptr;
Michael Wright1509a232018-06-21 02:50:34 +0100848 }
Dan Stoza030fbc12020-02-19 15:32:01 -0800849
Matt Buckley50c44062022-01-17 20:48:10 +0000850 // At this point, we know for sure there is no running session
Matt Buckley06f299a2021-09-24 19:43:51 +0000851 mPowerHintSessionRunning = false;
852
Dan Stoza030fbc12020-02-19 15:32:01 -0800853 // First attempt to connect to the AIDL Power HAL
854 sHalWrapper = AidlPowerHalWrapper::connect();
855
856 // If that didn't succeed, attempt to connect to the HIDL Power HAL
857 if (sHalWrapper == nullptr) {
858 sHalWrapper = HidlPowerHalWrapper::connect();
Xiang Wang65a2e6f2022-04-18 21:19:17 +0000859 } else {
860 ALOGD("Successfully connecting AIDL Power HAL");
Matt Buckley50c44062022-01-17 20:48:10 +0000861 // If AIDL, pass on any existing hint session values
Matt Buckley06f299a2021-09-24 19:43:51 +0000862 sHalWrapper->setPowerHintSessionThreadIds(oldPowerHintSessionThreadIds);
Matt Buckley50c44062022-01-17 20:48:10 +0000863 // Only set duration and start if duration is defined
Matt Buckley06f299a2021-09-24 19:43:51 +0000864 if (oldTargetWorkDuration.has_value()) {
865 sHalWrapper->setTargetWorkDuration(*oldTargetWorkDuration);
Matt Buckley50c44062022-01-17 20:48:10 +0000866 // Only start if possible to run and both threadids and duration are defined
Matt Buckley06f299a2021-09-24 19:43:51 +0000867 if (usePowerHintSession() && !oldPowerHintSessionThreadIds.empty()) {
868 mPowerHintSessionRunning = sHalWrapper->startPowerHintSession();
869 }
870 }
Dan Stoza030fbc12020-02-19 15:32:01 -0800871 }
872
Dan Stoza9c051c02020-02-28 10:19:07 -0800873 // If we make it to this point and still don't have a HAL, it's unlikely we
874 // will, so stop trying
875 if (sHalWrapper == nullptr) {
876 sHasHal = false;
877 }
878
Dan Stoza030fbc12020-02-19 15:32:01 -0800879 return sHalWrapper.get();
Michael Wright1509a232018-06-21 02:50:34 +0100880}
881
882} // namespace impl
883} // namespace Hwc2
884} // namespace android