blob: 6f02843f1a6f46ecedff0f92f0e6a9b07607c37e [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
Michael Wright1509a232018-06-21 02:50:34 +010019#undef LOG_TAG
20#define LOG_TAG "PowerAdvisor"
21
Matt Buckley06f299a2021-09-24 19:43:51 +000022#include <unistd.h>
Michael Wright1509a232018-06-21 02:50:34 +010023#include <cinttypes>
Matt Buckley06f299a2021-09-24 19:43:51 +000024#include <cstdint>
25#include <optional>
Michael Wright1509a232018-06-21 02:50:34 +010026
Dan Stoza030fbc12020-02-19 15:32:01 -080027#include <android-base/properties.h>
Michael Wright1509a232018-06-21 02:50:34 +010028#include <utils/Log.h>
29#include <utils/Mutex.h>
30
Dan Stoza030fbc12020-02-19 15:32:01 -080031#include <android/hardware/power/1.3/IPower.h>
32#include <android/hardware/power/IPower.h>
Matt Buckley06f299a2021-09-24 19:43:51 +000033#include <android/hardware/power/IPowerHintSession.h>
34#include <android/hardware/power/WorkDuration.h>
35
Dan Stoza030fbc12020-02-19 15:32:01 -080036#include <binder/IServiceManager.h>
37
38#include "../SurfaceFlingerProperties.h"
39
Michael Wright1509a232018-06-21 02:50:34 +010040#include "PowerAdvisor.h"
Alec Mouridea1ac52021-06-23 18:12:18 -070041#include "SurfaceFlinger.h"
Michael Wright1509a232018-06-21 02:50:34 +010042
43namespace android {
44namespace Hwc2 {
45
46PowerAdvisor::~PowerAdvisor() = default;
47
48namespace impl {
49
50namespace V1_0 = android::hardware::power::V1_0;
Dan Stoza030fbc12020-02-19 15:32:01 -080051namespace V1_3 = android::hardware::power::V1_3;
Michael Wright1509a232018-06-21 02:50:34 +010052using V1_3::PowerHint;
53
Dan Stoza030fbc12020-02-19 15:32:01 -080054using android::hardware::power::Boost;
55using android::hardware::power::IPower;
Matt Buckley06f299a2021-09-24 19:43:51 +000056using android::hardware::power::IPowerHintSession;
Dan Stoza030fbc12020-02-19 15:32:01 -080057using android::hardware::power::Mode;
Matt Buckley06f299a2021-09-24 19:43:51 +000058using android::hardware::power::WorkDuration;
59
Dan Stoza030fbc12020-02-19 15:32:01 -080060using scheduler::OneShotTimer;
61
Matt Buckley06f299a2021-09-24 19:43:51 +000062class AidlPowerHalWrapper;
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
73} // namespace
74
Alec Mouridea1ac52021-06-23 18:12:18 -070075PowerAdvisor::PowerAdvisor(SurfaceFlinger& flinger)
76 : mFlinger(flinger),
77 mUseScreenUpdateTimer(getUpdateTimeout() > 0),
78 mScreenUpdateTimer(
Ady Abrahamdb3dfee2020-11-17 17:07:12 -080079 "UpdateImminentTimer", OneShotTimer::Interval(getUpdateTimeout()),
Dan Stoza030fbc12020-02-19 15:32:01 -080080 /* resetCallback */ [this] { mSendUpdateImminent.store(false); },
Alec Mouridea1ac52021-06-23 18:12:18 -070081 /* timeoutCallback */
82 [this] {
83 mSendUpdateImminent.store(true);
84 mFlinger.disableExpensiveRendering();
85 }) {}
86
87void PowerAdvisor::init() {
88 // Defer starting the screen update timer until SurfaceFlinger finishes construction.
89 if (mUseScreenUpdateTimer) {
90 mScreenUpdateTimer.start();
Dan Stoza030fbc12020-02-19 15:32:01 -080091 }
92}
Michael Wright1509a232018-06-21 02:50:34 +010093
Dan Stoza29e7bdf2020-03-23 14:43:09 -070094void PowerAdvisor::onBootFinished() {
95 mBootFinished.store(true);
96}
97
Peiyong Lin74ca2f42019-01-14 19:36:57 -080098void PowerAdvisor::setExpensiveRenderingExpected(DisplayId displayId, bool expected) {
Michael Wright1509a232018-06-21 02:50:34 +010099 if (expected) {
100 mExpensiveDisplays.insert(displayId);
101 } else {
102 mExpensiveDisplays.erase(displayId);
103 }
104
Michael Wright1509a232018-06-21 02:50:34 +0100105 const bool expectsExpensiveRendering = !mExpensiveDisplays.empty();
106 if (mNotifiedExpensiveRendering != expectsExpensiveRendering) {
Dan Stoza20950002020-06-18 14:56:58 -0700107 std::lock_guard lock(mPowerHalMutex);
Dan Stoza030fbc12020-02-19 15:32:01 -0800108 HalWrapper* const halWrapper = getPowerHal();
109 if (halWrapper == nullptr) {
Peiyong Lin81934972018-07-02 11:00:54 -0700110 return;
111 }
Dan Stoza030fbc12020-02-19 15:32:01 -0800112
113 if (!halWrapper->setExpensiveRendering(expectsExpensiveRendering)) {
114 // The HAL has become unavailable; attempt to reconnect later
Michael Wright1509a232018-06-21 02:50:34 +0100115 mReconnectPowerHal = true;
116 return;
117 }
Dan Stoza030fbc12020-02-19 15:32:01 -0800118
Michael Wright1509a232018-06-21 02:50:34 +0100119 mNotifiedExpensiveRendering = expectsExpensiveRendering;
120 }
121}
122
Dan Stoza030fbc12020-02-19 15:32:01 -0800123void PowerAdvisor::notifyDisplayUpdateImminent() {
Dan Stoza29e7bdf2020-03-23 14:43:09 -0700124 // Only start sending this notification once the system has booted so we don't introduce an
125 // early-boot dependency on Power HAL
126 if (!mBootFinished.load()) {
127 return;
128 }
129
Dan Stoza030fbc12020-02-19 15:32:01 -0800130 if (mSendUpdateImminent.load()) {
Dan Stoza20950002020-06-18 14:56:58 -0700131 std::lock_guard lock(mPowerHalMutex);
Dan Stoza030fbc12020-02-19 15:32:01 -0800132 HalWrapper* const halWrapper = getPowerHal();
133 if (halWrapper == nullptr) {
134 return;
135 }
136
137 if (!halWrapper->notifyDisplayUpdateImminent()) {
138 // The HAL has become unavailable; attempt to reconnect later
139 mReconnectPowerHal = true;
140 return;
141 }
142 }
143
Alec Mouridea1ac52021-06-23 18:12:18 -0700144 if (mUseScreenUpdateTimer) {
145 mScreenUpdateTimer.reset();
Dan Stoza030fbc12020-02-19 15:32:01 -0800146 }
147}
148
Matt Buckley06f299a2021-09-24 19:43:51 +0000149// checks both if it supports and if it's enabled
150bool PowerAdvisor::usePowerHintSession() {
151 // uses cached value since the underlying support and flag are unlikely to change at runtime
Matt Buckley06f299a2021-09-24 19:43:51 +0000152 return mPowerHintEnabled.value_or(false) && supportsPowerHintSession();
153}
154
155bool PowerAdvisor::supportsPowerHintSession() {
156 // cache to avoid needing lock every time
157 if (!mSupportsPowerHint.has_value()) {
158 std::lock_guard lock(mPowerHalMutex);
159 HalWrapper* const halWrapper = getPowerHal();
160 mSupportsPowerHint = halWrapper->supportsPowerHintSession();
161 }
162 return *mSupportsPowerHint;
163}
164
165bool PowerAdvisor::isPowerHintSessionRunning() {
166 return mPowerHintSessionRunning;
167}
168
169void PowerAdvisor::setTargetWorkDuration(int64_t targetDurationNanos) {
Matt Buckleyef51fba2021-10-12 19:30:12 +0000170 if (!usePowerHintSession()) {
Matt Buckley06f299a2021-09-24 19:43:51 +0000171 ALOGV("Power hint session target duration cannot be set, skipping");
172 return;
173 }
174 {
175 std::lock_guard lock(mPowerHalMutex);
176 HalWrapper* const halWrapper = getPowerHal();
177 if (halWrapper != nullptr) {
Matt Buckleyef51fba2021-10-12 19:30:12 +0000178 halWrapper->setTargetWorkDuration(targetDurationNanos - kTargetSafetyMargin.count());
Matt Buckley06f299a2021-09-24 19:43:51 +0000179 }
180 }
181}
182
183void PowerAdvisor::sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timeStampNanos) {
184 if (!mBootFinished || !usePowerHintSession()) {
185 ALOGV("Actual work duration power hint cannot be sent, skipping");
186 return;
187 }
188 {
189 std::lock_guard lock(mPowerHalMutex);
190 HalWrapper* const halWrapper = getPowerHal();
191 if (halWrapper != nullptr) {
192 halWrapper->sendActualWorkDuration(actualDurationNanos, timeStampNanos);
193 }
194 }
195}
196
197// needs to be set after the flag is known but before PowerAdvisor enters onBootFinished
198void PowerAdvisor::enablePowerHint(bool enabled) {
199 mPowerHintEnabled = enabled;
200}
201
Matt Buckleyef51fba2021-10-12 19:30:12 +0000202bool PowerAdvisor::startPowerHintSession(const std::vector<int32_t>& threadIds) {
203 if (!usePowerHintSession()) {
204 ALOGI("Power hint session cannot be started, skipping");
205 }
206 {
207 std::lock_guard lock(mPowerHalMutex);
208 HalWrapper* halWrapper = getPowerHal();
209 if (halWrapper != nullptr && usePowerHintSession()) {
210 halWrapper->setPowerHintSessionThreadIds(threadIds);
211 mPowerHintSessionRunning = halWrapper->startPowerHintSession();
212 }
213 }
214 return mPowerHintSessionRunning;
215}
216
Dan Stoza030fbc12020-02-19 15:32:01 -0800217class HidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
218public:
219 HidlPowerHalWrapper(sp<V1_3::IPower> powerHal) : mPowerHal(std::move(powerHal)) {}
220
221 ~HidlPowerHalWrapper() override = default;
222
223 static std::unique_ptr<HalWrapper> connect() {
224 // Power HAL 1.3 is not guaranteed to be available, thus we need to query
225 // Power HAL 1.0 first and try to cast it to Power HAL 1.3.
Dan Stoza030fbc12020-02-19 15:32:01 -0800226 sp<V1_3::IPower> powerHal = nullptr;
Dan Stoza9c051c02020-02-28 10:19:07 -0800227 sp<V1_0::IPower> powerHal_1_0 = V1_0::IPower::getService();
228 if (powerHal_1_0 != nullptr) {
229 // Try to cast to Power HAL 1.3
230 powerHal = V1_3::IPower::castFrom(powerHal_1_0);
231 if (powerHal == nullptr) {
232 ALOGW("No Power HAL 1.3 service in system, disabling PowerAdvisor");
233 } else {
234 ALOGI("Loaded Power HAL 1.3 service");
Dan Stoza030fbc12020-02-19 15:32:01 -0800235 }
Dan Stoza9c051c02020-02-28 10:19:07 -0800236 } else {
237 ALOGW("No Power HAL found, disabling PowerAdvisor");
Dan Stoza030fbc12020-02-19 15:32:01 -0800238 }
Dan Stoza9c051c02020-02-28 10:19:07 -0800239
Dan Stoza030fbc12020-02-19 15:32:01 -0800240 if (powerHal == nullptr) {
241 return nullptr;
242 }
243
244 return std::make_unique<HidlPowerHalWrapper>(std::move(powerHal));
245 }
246
247 bool setExpensiveRendering(bool enabled) override {
248 ALOGV("HIDL setExpensiveRendering %s", enabled ? "T" : "F");
249 auto ret = mPowerHal->powerHintAsync_1_3(PowerHint::EXPENSIVE_RENDERING, enabled);
250 return ret.isOk();
251 }
252
253 bool notifyDisplayUpdateImminent() override {
254 // Power HAL 1.x doesn't have a notification for this
255 ALOGV("HIDL notifyUpdateImminent received but can't send");
256 return true;
257 }
258
Matt Buckley06f299a2021-09-24 19:43:51 +0000259 bool supportsPowerHintSession() override { return false; }
260
261 bool isPowerHintSessionRunning() override { return false; }
262
263 void restartPowerHintSession() override {}
264
265 void setPowerHintSessionThreadIds(const std::vector<int32_t>&) override {}
266
267 bool startPowerHintSession() override { return false; }
268
269 void setTargetWorkDuration(int64_t) override {}
270
271 void sendActualWorkDuration(int64_t, nsecs_t) override {}
272
273 bool shouldReconnectHAL() override { return false; }
274
275 std::vector<int32_t> getPowerHintSessionThreadIds() override { return std::vector<int32_t>{}; }
276
277 std::optional<int64_t> getTargetWorkDuration() override { return std::nullopt; }
278
Dan Stoza030fbc12020-02-19 15:32:01 -0800279private:
Dan Stoza030fbc12020-02-19 15:32:01 -0800280 const sp<V1_3::IPower> mPowerHal = nullptr;
281};
282
Dan Stoza030fbc12020-02-19 15:32:01 -0800283class AidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
284public:
285 AidlPowerHalWrapper(sp<IPower> powerHal) : mPowerHal(std::move(powerHal)) {
286 auto ret = mPowerHal->isModeSupported(Mode::EXPENSIVE_RENDERING, &mHasExpensiveRendering);
287 if (!ret.isOk()) {
288 mHasExpensiveRendering = false;
289 }
290
291 ret = mPowerHal->isBoostSupported(Boost::DISPLAY_UPDATE_IMMINENT,
292 &mHasDisplayUpdateImminent);
293 if (!ret.isOk()) {
294 mHasDisplayUpdateImminent = false;
295 }
Matt Buckley06f299a2021-09-24 19:43:51 +0000296
Matt Buckleyef51fba2021-10-12 19:30:12 +0000297 mSupportsPowerHint = checkPowerHintSessionSupported();
Dan Stoza030fbc12020-02-19 15:32:01 -0800298 }
299
Matt Buckley06f299a2021-09-24 19:43:51 +0000300 ~AidlPowerHalWrapper() override {
301 if (mPowerHintSession != nullptr) {
302 mPowerHintSession->close();
303 mPowerHintSession = nullptr;
304 }
305 };
Dan Stoza030fbc12020-02-19 15:32:01 -0800306
307 static std::unique_ptr<HalWrapper> connect() {
308 // This only waits if the service is actually declared
309 sp<IPower> powerHal = waitForVintfService<IPower>();
310 if (powerHal == nullptr) {
311 return nullptr;
312 }
313 ALOGI("Loaded AIDL Power HAL service");
314
315 return std::make_unique<AidlPowerHalWrapper>(std::move(powerHal));
316 }
317
318 bool setExpensiveRendering(bool enabled) override {
319 ALOGV("AIDL setExpensiveRendering %s", enabled ? "T" : "F");
320 if (!mHasExpensiveRendering) {
321 ALOGV("Skipped sending EXPENSIVE_RENDERING because HAL doesn't support it");
322 return true;
323 }
324
325 auto ret = mPowerHal->setMode(Mode::EXPENSIVE_RENDERING, enabled);
326 return ret.isOk();
327 }
328
329 bool notifyDisplayUpdateImminent() override {
330 ALOGV("AIDL notifyDisplayUpdateImminent");
331 if (!mHasDisplayUpdateImminent) {
332 ALOGV("Skipped sending DISPLAY_UPDATE_IMMINENT because HAL doesn't support it");
333 return true;
334 }
335
336 auto ret = mPowerHal->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 0);
337 return ret.isOk();
338 }
339
Matt Buckley06f299a2021-09-24 19:43:51 +0000340 // only version 2+ of the aidl supports power hint sessions, hidl has no support
Matt Buckleyef51fba2021-10-12 19:30:12 +0000341 bool supportsPowerHintSession() override { return mSupportsPowerHint; }
342
343 bool checkPowerHintSessionSupported() {
344 int64_t unused;
345 // Try to get preferred rate to determine if hint sessions are supported
346 // We check for isOk not EX_UNSUPPORTED_OPERATION to lump other errors
347 return mPowerHal->getHintSessionPreferredRate(&unused).isOk();
348 }
Matt Buckley06f299a2021-09-24 19:43:51 +0000349
350 bool isPowerHintSessionRunning() override { return mPowerHintSession != nullptr; }
351
352 void closePowerHintSession() {
353 if (mPowerHintSession != nullptr) {
354 mPowerHintSession->close();
355 mPowerHintSession = nullptr;
356 }
357 }
358
359 void restartPowerHintSession() {
360 closePowerHintSession();
361 startPowerHintSession();
362 }
363
364 void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) override {
365 if (threadIds != mPowerHintThreadIds) {
366 mPowerHintThreadIds = threadIds;
367 if (isPowerHintSessionRunning()) {
368 restartPowerHintSession();
369 }
370 }
371 }
372
373 bool startPowerHintSession() override {
Matt Buckleyef51fba2021-10-12 19:30:12 +0000374 if (mPowerHintSession != nullptr || mPowerHintThreadIds.empty()) {
Matt Buckley06f299a2021-09-24 19:43:51 +0000375 ALOGV("Cannot start power hint session, skipping");
376 return false;
377 }
378 auto ret = mPowerHal->createHintSession(getpid(), static_cast<int32_t>(getuid()),
Matt Buckleyef51fba2021-10-12 19:30:12 +0000379 mPowerHintThreadIds, mTargetDuration,
Matt Buckley06f299a2021-09-24 19:43:51 +0000380 &mPowerHintSession);
381 if (!ret.isOk()) {
382 ALOGW("Failed to start power hint session with error: %s",
383 ret.exceptionToString(ret.exceptionCode()).c_str());
Matt Buckleyef51fba2021-10-12 19:30:12 +0000384 } else {
385 mLastTargetDurationSent = mTargetDuration;
Matt Buckley06f299a2021-09-24 19:43:51 +0000386 }
387 return isPowerHintSessionRunning();
388 }
389
390 bool shouldSetTargetDuration(int64_t targetDurationNanos) {
Matt Buckley06f299a2021-09-24 19:43:51 +0000391 // report if the change in target from our last submission to now exceeds the threshold
392 return abs(1.0 -
Matt Buckleyef51fba2021-10-12 19:30:12 +0000393 static_cast<double>(mLastTargetDurationSent) /
Matt Buckley06f299a2021-09-24 19:43:51 +0000394 static_cast<double>(targetDurationNanos)) >=
Matt Buckleyef51fba2021-10-12 19:30:12 +0000395 kAllowedTargetDeviationPercent;
Matt Buckley06f299a2021-09-24 19:43:51 +0000396 }
397
398 void setTargetWorkDuration(int64_t targetDurationNanos) override {
Matt Buckleyef51fba2021-10-12 19:30:12 +0000399 ATRACE_CALL();
400 mTargetDuration = targetDurationNanos;
401 if (sTraceHintSessionData) ATRACE_INT64("Time target", targetDurationNanos);
402 if (!sNormalizeTarget && shouldSetTargetDuration(targetDurationNanos) &&
403 isPowerHintSessionRunning()) {
404 if (mLastActualDurationSent.has_value()) {
405 // update the error term here since we are actually sending an update to powerhal
406 if (sTraceHintSessionData)
407 ATRACE_INT64("Target error term",
408 targetDurationNanos - *mLastActualDurationSent);
409 }
410 ALOGV("Sending target time: %lld ns", static_cast<long long>(targetDurationNanos));
Matt Buckley06f299a2021-09-24 19:43:51 +0000411 mLastTargetDurationSent = targetDurationNanos;
412 auto ret = mPowerHintSession->updateTargetWorkDuration(targetDurationNanos);
413 if (!ret.isOk()) {
414 ALOGW("Failed to set power hint target work duration with error: %s",
415 ret.exceptionMessage().c_str());
416 mShouldReconnectHal = true;
417 }
418 }
419 }
420
421 bool shouldReportActualDurationsNow() {
Matt Buckley5793e162022-01-11 20:35:26 +0000422 // report if we have never reported before or are approaching a stale session
423 if (!mLastActualDurationSent.has_value() ||
424 (systemTime() - mLastActualReportTimestamp) > kStaleTimeout.count()) {
Matt Buckley06f299a2021-09-24 19:43:51 +0000425 return true;
426 }
427
Matt Buckleyef51fba2021-10-12 19:30:12 +0000428 if (!mActualDuration.has_value()) {
429 return false;
430 }
431
Matt Buckley06f299a2021-09-24 19:43:51 +0000432 // duration of most recent timing
Matt Buckleyef51fba2021-10-12 19:30:12 +0000433 const double mostRecentActualDuration = static_cast<double>(*mActualDuration);
Matt Buckley06f299a2021-09-24 19:43:51 +0000434 // duration of the last timing actually reported to the powerhal
Matt Buckleyef51fba2021-10-12 19:30:12 +0000435 const double lastReportedActualDuration = static_cast<double>(*mLastActualDurationSent);
Matt Buckley06f299a2021-09-24 19:43:51 +0000436
437 // report if the change in duration from then to now exceeds the threshold
438 return abs(1.0 - mostRecentActualDuration / lastReportedActualDuration) >=
Matt Buckleyef51fba2021-10-12 19:30:12 +0000439 kAllowedActualDeviationPercent;
Matt Buckley06f299a2021-09-24 19:43:51 +0000440 }
441
442 void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timeStampNanos) override {
Matt Buckleyef51fba2021-10-12 19:30:12 +0000443 ATRACE_CALL();
444
Matt Buckley06f299a2021-09-24 19:43:51 +0000445 if (actualDurationNanos < 0 || !isPowerHintSessionRunning()) {
446 ALOGV("Failed to send actual work duration, skipping");
447 return;
448 }
449
450 WorkDuration duration;
451 duration.durationNanos = actualDurationNanos;
Matt Buckleyef51fba2021-10-12 19:30:12 +0000452 mActualDuration = actualDurationNanos;
453
454 // normalize the sent values to a pre-set target
455 if (sNormalizeTarget) {
456 duration.durationNanos += mLastTargetDurationSent - mTargetDuration;
457 }
Matt Buckley06f299a2021-09-24 19:43:51 +0000458 duration.timeStampNanos = timeStampNanos;
459 mPowerHintQueue.push_back(duration);
460
Matt Buckleyef51fba2021-10-12 19:30:12 +0000461 long long targetNsec = mTargetDuration;
462 long long durationNsec = actualDurationNanos;
463
464 if (sTraceHintSessionData) {
465 ATRACE_INT64("Measured duration", durationNsec);
466 ATRACE_INT64("Target error term", targetNsec - durationNsec);
467 }
468
469 ALOGV("Sending actual work duration of: %lld on target: %lld with error: %lld",
470 durationNsec, targetNsec, targetNsec - durationNsec);
471
Matt Buckley06f299a2021-09-24 19:43:51 +0000472 // This rate limiter queues similar duration reports to the powerhal into
473 // batches to avoid excessive binder calls. The criteria to send a given batch
474 // are outlined in shouldReportActualDurationsNow()
475 if (shouldReportActualDurationsNow()) {
Matt Buckleyef51fba2021-10-12 19:30:12 +0000476 ALOGV("Sending hint update batch");
Matt Buckley5793e162022-01-11 20:35:26 +0000477 mLastActualReportTimestamp = systemTime();
Matt Buckley06f299a2021-09-24 19:43:51 +0000478 auto ret = mPowerHintSession->reportActualWorkDuration(mPowerHintQueue);
479 if (!ret.isOk()) {
480 ALOGW("Failed to report actual work durations with error: %s",
481 ret.exceptionMessage().c_str());
482 mShouldReconnectHal = true;
483 }
484 mPowerHintQueue.clear();
Matt Buckleyef51fba2021-10-12 19:30:12 +0000485 // we save the non-normalized value here to detect % changes
486 mLastActualDurationSent = actualDurationNanos;
Matt Buckley06f299a2021-09-24 19:43:51 +0000487 }
488 }
489
490 bool shouldReconnectHAL() override { return mShouldReconnectHal; }
491
492 std::vector<int32_t> getPowerHintSessionThreadIds() override { return mPowerHintThreadIds; }
493
Matt Buckleyef51fba2021-10-12 19:30:12 +0000494 std::optional<int64_t> getTargetWorkDuration() override { return mTargetDuration; }
Matt Buckley06f299a2021-09-24 19:43:51 +0000495
Dan Stoza030fbc12020-02-19 15:32:01 -0800496private:
497 const sp<IPower> mPowerHal = nullptr;
498 bool mHasExpensiveRendering = false;
499 bool mHasDisplayUpdateImminent = false;
Matt Buckleyef51fba2021-10-12 19:30:12 +0000500 // Used to indicate an error state and need for reconstruction
501 bool mShouldReconnectHal = false;
Matt Buckley06f299a2021-09-24 19:43:51 +0000502 // This is not thread safe, but is currently protected by mPowerHalMutex so it needs no lock
503 sp<IPowerHintSession> mPowerHintSession = nullptr;
Matt Buckleyef51fba2021-10-12 19:30:12 +0000504 // Queue of actual durations saved to report
Matt Buckley06f299a2021-09-24 19:43:51 +0000505 std::vector<WorkDuration> mPowerHintQueue;
Matt Buckleyef51fba2021-10-12 19:30:12 +0000506 // The latest un-normalized values we have received for target and actual
Matt Buckley5793e162022-01-11 20:35:26 +0000507 int64_t mTargetDuration = kDefaultTarget.count();
Matt Buckleyef51fba2021-10-12 19:30:12 +0000508 std::optional<int64_t> mActualDuration;
509 // The list of thread ids, stored so we can restart the session from this class if needed
Matt Buckley06f299a2021-09-24 19:43:51 +0000510 std::vector<int32_t> mPowerHintThreadIds;
Matt Buckleyef51fba2021-10-12 19:30:12 +0000511 bool mSupportsPowerHint;
512 // Keep track of the last messages sent for rate limiter change detection
513 std::optional<int64_t> mLastActualDurationSent;
Matt Buckley5793e162022-01-11 20:35:26 +0000514 // timestamp of the last report we sent, used to avoid stale sessions
515 int64_t mLastActualReportTimestamp = 0;
516 int64_t mLastTargetDurationSent = kDefaultTarget.count();
Matt Buckleyef51fba2021-10-12 19:30:12 +0000517 // Whether to normalize all the actual values as error terms relative to a constant target
518 // This saves a binder call by not setting the target, and should not affect the pid values
519 static const bool sNormalizeTarget;
520 // Whether we should emit ATRACE_INT data for hint sessions
521 static const bool sTraceHintSessionData;
Matt Buckleyef51fba2021-10-12 19:30:12 +0000522 // Max percent the actual duration can vary without causing a report (eg: 0.1 = 10%)
523 static constexpr double kAllowedActualDeviationPercent = 0.1;
524 // Max percent the target duration can vary without causing a report (eg: 0.05 = 5%)
525 static constexpr double kAllowedTargetDeviationPercent = 0.05;
526 // Target used for init and normalization, the actual value does not really matter
Matt Buckley5793e162022-01-11 20:35:26 +0000527 static constexpr const std::chrono::nanoseconds kDefaultTarget = 50ms;
528 // amount of time after the last message was sent before the session goes stale
529 // actually 100ms but we use 80 here to ideally avoid going stale
530 static constexpr const std::chrono::nanoseconds kStaleTimeout = 80ms;
Dan Stoza030fbc12020-02-19 15:32:01 -0800531};
532
Matt Buckleyef51fba2021-10-12 19:30:12 +0000533const bool AidlPowerHalWrapper::sTraceHintSessionData =
534 base::GetBoolProperty(std::string("debug.sf.trace_hint_sessions"), false);
535
536const bool AidlPowerHalWrapper::sNormalizeTarget =
537 base::GetBoolProperty(std::string("debug.sf.normalize_hint_session_durations"), true);
538
Dan Stoza030fbc12020-02-19 15:32:01 -0800539PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() {
540 static std::unique_ptr<HalWrapper> sHalWrapper = nullptr;
Dan Stoza9c051c02020-02-28 10:19:07 -0800541 static bool sHasHal = true;
Michael Wright1509a232018-06-21 02:50:34 +0100542
Dan Stoza9c051c02020-02-28 10:19:07 -0800543 if (!sHasHal) {
544 return nullptr;
545 }
546
Matt Buckley06f299a2021-09-24 19:43:51 +0000547 // grab old hint session values before we destroy any existing wrapper
548 std::vector<int32_t> oldPowerHintSessionThreadIds;
549 std::optional<int64_t> oldTargetWorkDuration;
550
551 if (sHalWrapper != nullptr) {
552 oldPowerHintSessionThreadIds = sHalWrapper->getPowerHintSessionThreadIds();
553 oldTargetWorkDuration = sHalWrapper->getTargetWorkDuration();
554 }
555
Dan Stoza9c051c02020-02-28 10:19:07 -0800556 // If we used to have a HAL, but it stopped responding, attempt to reconnect
Michael Wright1509a232018-06-21 02:50:34 +0100557 if (mReconnectPowerHal) {
Dan Stoza030fbc12020-02-19 15:32:01 -0800558 sHalWrapper = nullptr;
Michael Wright1509a232018-06-21 02:50:34 +0100559 mReconnectPowerHal = false;
560 }
561
Dan Stoza030fbc12020-02-19 15:32:01 -0800562 if (sHalWrapper != nullptr) {
Matt Buckley06f299a2021-09-24 19:43:51 +0000563 auto wrapper = sHalWrapper.get();
564 // if the wrapper is fine, return it, but if it indicates a reconnect, remake it
565 if (!wrapper->shouldReconnectHAL()) {
566 return wrapper;
567 }
568 sHalWrapper = nullptr;
Michael Wright1509a232018-06-21 02:50:34 +0100569 }
Dan Stoza030fbc12020-02-19 15:32:01 -0800570
Matt Buckley06f299a2021-09-24 19:43:51 +0000571 // at this point, we know for sure there is no running session
572 mPowerHintSessionRunning = false;
573
Dan Stoza030fbc12020-02-19 15:32:01 -0800574 // First attempt to connect to the AIDL Power HAL
575 sHalWrapper = AidlPowerHalWrapper::connect();
576
577 // If that didn't succeed, attempt to connect to the HIDL Power HAL
578 if (sHalWrapper == nullptr) {
579 sHalWrapper = HidlPowerHalWrapper::connect();
Matt Buckley06f299a2021-09-24 19:43:51 +0000580 } else { // if AIDL, pass on any existing hint session values
581 // thread ids always safe to set
582 sHalWrapper->setPowerHintSessionThreadIds(oldPowerHintSessionThreadIds);
583 // only set duration and start if duration is defined
584 if (oldTargetWorkDuration.has_value()) {
585 sHalWrapper->setTargetWorkDuration(*oldTargetWorkDuration);
586 // only start if possible to run and both threadids and duration are defined
587 if (usePowerHintSession() && !oldPowerHintSessionThreadIds.empty()) {
588 mPowerHintSessionRunning = sHalWrapper->startPowerHintSession();
589 }
590 }
Dan Stoza030fbc12020-02-19 15:32:01 -0800591 }
592
Dan Stoza9c051c02020-02-28 10:19:07 -0800593 // If we make it to this point and still don't have a HAL, it's unlikely we
594 // will, so stop trying
595 if (sHalWrapper == nullptr) {
596 sHasHal = false;
597 }
598
Dan Stoza030fbc12020-02-19 15:32:01 -0800599 return sHalWrapper.get();
Michael Wright1509a232018-06-21 02:50:34 +0100600}
601
602} // namespace impl
603} // namespace Hwc2
604} // namespace android