blob: 930ddea08918620753b81a798e81d8d1aa062002 [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();
Matt Buckley06f299a2021-09-24 19:43:51 +0000298
Matt Buckleyef51fba2021-10-12 19:30:12 +0000299 if (mSupportsPowerHint) {
300 mPowerHintQueue.reserve(kMaxQueueSize);
Matt Buckley06f299a2021-09-24 19:43:51 +0000301 }
Dan Stoza030fbc12020-02-19 15:32:01 -0800302 }
303
Matt Buckley06f299a2021-09-24 19:43:51 +0000304 ~AidlPowerHalWrapper() override {
305 if (mPowerHintSession != nullptr) {
306 mPowerHintSession->close();
307 mPowerHintSession = nullptr;
308 }
309 };
Dan Stoza030fbc12020-02-19 15:32:01 -0800310
311 static std::unique_ptr<HalWrapper> connect() {
312 // This only waits if the service is actually declared
313 sp<IPower> powerHal = waitForVintfService<IPower>();
314 if (powerHal == nullptr) {
315 return nullptr;
316 }
317 ALOGI("Loaded AIDL Power HAL service");
318
319 return std::make_unique<AidlPowerHalWrapper>(std::move(powerHal));
320 }
321
322 bool setExpensiveRendering(bool enabled) override {
323 ALOGV("AIDL setExpensiveRendering %s", enabled ? "T" : "F");
324 if (!mHasExpensiveRendering) {
325 ALOGV("Skipped sending EXPENSIVE_RENDERING because HAL doesn't support it");
326 return true;
327 }
328
329 auto ret = mPowerHal->setMode(Mode::EXPENSIVE_RENDERING, enabled);
330 return ret.isOk();
331 }
332
333 bool notifyDisplayUpdateImminent() override {
334 ALOGV("AIDL notifyDisplayUpdateImminent");
335 if (!mHasDisplayUpdateImminent) {
336 ALOGV("Skipped sending DISPLAY_UPDATE_IMMINENT because HAL doesn't support it");
337 return true;
338 }
339
340 auto ret = mPowerHal->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 0);
341 return ret.isOk();
342 }
343
Matt Buckley06f299a2021-09-24 19:43:51 +0000344 // only version 2+ of the aidl supports power hint sessions, hidl has no support
Matt Buckleyef51fba2021-10-12 19:30:12 +0000345 bool supportsPowerHintSession() override { return mSupportsPowerHint; }
346
347 bool checkPowerHintSessionSupported() {
348 int64_t unused;
349 // Try to get preferred rate to determine if hint sessions are supported
350 // We check for isOk not EX_UNSUPPORTED_OPERATION to lump other errors
351 return mPowerHal->getHintSessionPreferredRate(&unused).isOk();
352 }
Matt Buckley06f299a2021-09-24 19:43:51 +0000353
354 bool isPowerHintSessionRunning() override { return mPowerHintSession != nullptr; }
355
356 void closePowerHintSession() {
357 if (mPowerHintSession != nullptr) {
358 mPowerHintSession->close();
359 mPowerHintSession = nullptr;
360 }
361 }
362
363 void restartPowerHintSession() {
364 closePowerHintSession();
365 startPowerHintSession();
366 }
367
368 void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) override {
369 if (threadIds != mPowerHintThreadIds) {
370 mPowerHintThreadIds = threadIds;
371 if (isPowerHintSessionRunning()) {
372 restartPowerHintSession();
373 }
374 }
375 }
376
377 bool startPowerHintSession() override {
Matt Buckleyef51fba2021-10-12 19:30:12 +0000378 if (mPowerHintSession != nullptr || mPowerHintThreadIds.empty()) {
Matt Buckley06f299a2021-09-24 19:43:51 +0000379 ALOGV("Cannot start power hint session, skipping");
380 return false;
381 }
382 auto ret = mPowerHal->createHintSession(getpid(), static_cast<int32_t>(getuid()),
Matt Buckleyef51fba2021-10-12 19:30:12 +0000383 mPowerHintThreadIds, mTargetDuration,
Matt Buckley06f299a2021-09-24 19:43:51 +0000384 &mPowerHintSession);
385 if (!ret.isOk()) {
386 ALOGW("Failed to start power hint session with error: %s",
387 ret.exceptionToString(ret.exceptionCode()).c_str());
Matt Buckleyef51fba2021-10-12 19:30:12 +0000388 } else {
389 mLastTargetDurationSent = mTargetDuration;
Matt Buckley06f299a2021-09-24 19:43:51 +0000390 }
391 return isPowerHintSessionRunning();
392 }
393
394 bool shouldSetTargetDuration(int64_t targetDurationNanos) {
Matt Buckley06f299a2021-09-24 19:43:51 +0000395 // report if the change in target from our last submission to now exceeds the threshold
396 return abs(1.0 -
Matt Buckleyef51fba2021-10-12 19:30:12 +0000397 static_cast<double>(mLastTargetDurationSent) /
Matt Buckley06f299a2021-09-24 19:43:51 +0000398 static_cast<double>(targetDurationNanos)) >=
Matt Buckleyef51fba2021-10-12 19:30:12 +0000399 kAllowedTargetDeviationPercent;
Matt Buckley06f299a2021-09-24 19:43:51 +0000400 }
401
402 void setTargetWorkDuration(int64_t targetDurationNanos) override {
Matt Buckleyef51fba2021-10-12 19:30:12 +0000403 ATRACE_CALL();
404 mTargetDuration = targetDurationNanos;
405 if (sTraceHintSessionData) ATRACE_INT64("Time target", targetDurationNanos);
406 if (!sNormalizeTarget && shouldSetTargetDuration(targetDurationNanos) &&
407 isPowerHintSessionRunning()) {
408 if (mLastActualDurationSent.has_value()) {
409 // update the error term here since we are actually sending an update to powerhal
410 if (sTraceHintSessionData)
411 ATRACE_INT64("Target error term",
412 targetDurationNanos - *mLastActualDurationSent);
413 }
414 ALOGV("Sending target time: %lld ns", static_cast<long long>(targetDurationNanos));
Matt Buckley06f299a2021-09-24 19:43:51 +0000415 mLastTargetDurationSent = targetDurationNanos;
416 auto ret = mPowerHintSession->updateTargetWorkDuration(targetDurationNanos);
417 if (!ret.isOk()) {
418 ALOGW("Failed to set power hint target work duration with error: %s",
419 ret.exceptionMessage().c_str());
420 mShouldReconnectHal = true;
421 }
422 }
423 }
424
425 bool shouldReportActualDurationsNow() {
426 // report if we have never reported before or have exceeded the max queue size
Matt Buckleyef51fba2021-10-12 19:30:12 +0000427 if (!mLastActualDurationSent.has_value() || mPowerHintQueue.size() >= kMaxQueueSize) {
Matt Buckley06f299a2021-09-24 19:43:51 +0000428 return true;
429 }
430
Matt Buckleyef51fba2021-10-12 19:30:12 +0000431 if (!mActualDuration.has_value()) {
432 return false;
433 }
434
Matt Buckley06f299a2021-09-24 19:43:51 +0000435 // duration of most recent timing
Matt Buckleyef51fba2021-10-12 19:30:12 +0000436 const double mostRecentActualDuration = static_cast<double>(*mActualDuration);
Matt Buckley06f299a2021-09-24 19:43:51 +0000437 // duration of the last timing actually reported to the powerhal
Matt Buckleyef51fba2021-10-12 19:30:12 +0000438 const double lastReportedActualDuration = static_cast<double>(*mLastActualDurationSent);
Matt Buckley06f299a2021-09-24 19:43:51 +0000439
440 // report if the change in duration from then to now exceeds the threshold
441 return abs(1.0 - mostRecentActualDuration / lastReportedActualDuration) >=
Matt Buckleyef51fba2021-10-12 19:30:12 +0000442 kAllowedActualDeviationPercent;
Matt Buckley06f299a2021-09-24 19:43:51 +0000443 }
444
445 void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timeStampNanos) override {
Matt Buckleyef51fba2021-10-12 19:30:12 +0000446 ATRACE_CALL();
447
Matt Buckley06f299a2021-09-24 19:43:51 +0000448 if (actualDurationNanos < 0 || !isPowerHintSessionRunning()) {
449 ALOGV("Failed to send actual work duration, skipping");
450 return;
451 }
452
453 WorkDuration duration;
454 duration.durationNanos = actualDurationNanos;
Matt Buckleyef51fba2021-10-12 19:30:12 +0000455 mActualDuration = actualDurationNanos;
456
457 // normalize the sent values to a pre-set target
458 if (sNormalizeTarget) {
459 duration.durationNanos += mLastTargetDurationSent - mTargetDuration;
460 }
Matt Buckley06f299a2021-09-24 19:43:51 +0000461 duration.timeStampNanos = timeStampNanos;
462 mPowerHintQueue.push_back(duration);
463
Matt Buckleyef51fba2021-10-12 19:30:12 +0000464 long long targetNsec = mTargetDuration;
465 long long durationNsec = actualDurationNanos;
466
467 if (sTraceHintSessionData) {
468 ATRACE_INT64("Measured duration", durationNsec);
469 ATRACE_INT64("Target error term", targetNsec - durationNsec);
470 }
471
472 ALOGV("Sending actual work duration of: %lld on target: %lld with error: %lld",
473 durationNsec, targetNsec, targetNsec - durationNsec);
474
Matt Buckley06f299a2021-09-24 19:43:51 +0000475 // This rate limiter queues similar duration reports to the powerhal into
476 // batches to avoid excessive binder calls. The criteria to send a given batch
477 // are outlined in shouldReportActualDurationsNow()
478 if (shouldReportActualDurationsNow()) {
Matt Buckleyef51fba2021-10-12 19:30:12 +0000479 ALOGV("Sending hint update batch");
Matt Buckley06f299a2021-09-24 19:43:51 +0000480 auto ret = mPowerHintSession->reportActualWorkDuration(mPowerHintQueue);
481 if (!ret.isOk()) {
482 ALOGW("Failed to report actual work durations with error: %s",
483 ret.exceptionMessage().c_str());
484 mShouldReconnectHal = true;
485 }
486 mPowerHintQueue.clear();
Matt Buckleyef51fba2021-10-12 19:30:12 +0000487 // we save the non-normalized value here to detect % changes
488 mLastActualDurationSent = actualDurationNanos;
Matt Buckley06f299a2021-09-24 19:43:51 +0000489 }
490 }
491
492 bool shouldReconnectHAL() override { return mShouldReconnectHal; }
493
494 std::vector<int32_t> getPowerHintSessionThreadIds() override { return mPowerHintThreadIds; }
495
Matt Buckleyef51fba2021-10-12 19:30:12 +0000496 std::optional<int64_t> getTargetWorkDuration() override { return mTargetDuration; }
Matt Buckley06f299a2021-09-24 19:43:51 +0000497
Dan Stoza030fbc12020-02-19 15:32:01 -0800498private:
499 const sp<IPower> mPowerHal = nullptr;
500 bool mHasExpensiveRendering = false;
501 bool mHasDisplayUpdateImminent = false;
Matt Buckleyef51fba2021-10-12 19:30:12 +0000502 // Used to indicate an error state and need for reconstruction
503 bool mShouldReconnectHal = false;
Matt Buckley06f299a2021-09-24 19:43:51 +0000504 // This is not thread safe, but is currently protected by mPowerHalMutex so it needs no lock
505 sp<IPowerHintSession> mPowerHintSession = nullptr;
Matt Buckleyef51fba2021-10-12 19:30:12 +0000506 // Queue of actual durations saved to report
Matt Buckley06f299a2021-09-24 19:43:51 +0000507 std::vector<WorkDuration> mPowerHintQueue;
Matt Buckleyef51fba2021-10-12 19:30:12 +0000508 // The latest un-normalized values we have received for target and actual
509 int64_t mTargetDuration = kDefaultTarget;
510 std::optional<int64_t> mActualDuration;
511 // The list of thread ids, stored so we can restart the session from this class if needed
Matt Buckley06f299a2021-09-24 19:43:51 +0000512 std::vector<int32_t> mPowerHintThreadIds;
Matt Buckleyef51fba2021-10-12 19:30:12 +0000513 bool mSupportsPowerHint;
514 // Keep track of the last messages sent for rate limiter change detection
515 std::optional<int64_t> mLastActualDurationSent;
516 int64_t mLastTargetDurationSent = kDefaultTarget;
517 // 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;
522 // Max number of messages allowed in mPowerHintQueue before reporting is forced
523 static constexpr int32_t kMaxQueueSize = 15;
524 // Max percent the actual duration can vary without causing a report (eg: 0.1 = 10%)
525 static constexpr double kAllowedActualDeviationPercent = 0.1;
526 // Max percent the target duration can vary without causing a report (eg: 0.05 = 5%)
527 static constexpr double kAllowedTargetDeviationPercent = 0.05;
528 // Target used for init and normalization, the actual value does not really matter
529 static constexpr int64_t kDefaultTarget = 50000000;
Dan Stoza030fbc12020-02-19 15:32:01 -0800530};
531
Matt Buckleyef51fba2021-10-12 19:30:12 +0000532const bool AidlPowerHalWrapper::sTraceHintSessionData =
533 base::GetBoolProperty(std::string("debug.sf.trace_hint_sessions"), false);
534
535const bool AidlPowerHalWrapper::sNormalizeTarget =
536 base::GetBoolProperty(std::string("debug.sf.normalize_hint_session_durations"), true);
537
Dan Stoza030fbc12020-02-19 15:32:01 -0800538PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() {
539 static std::unique_ptr<HalWrapper> sHalWrapper = nullptr;
Dan Stoza9c051c02020-02-28 10:19:07 -0800540 static bool sHasHal = true;
Michael Wright1509a232018-06-21 02:50:34 +0100541
Dan Stoza9c051c02020-02-28 10:19:07 -0800542 if (!sHasHal) {
543 return nullptr;
544 }
545
Matt Buckley06f299a2021-09-24 19:43:51 +0000546 // grab old hint session values before we destroy any existing wrapper
547 std::vector<int32_t> oldPowerHintSessionThreadIds;
548 std::optional<int64_t> oldTargetWorkDuration;
549
550 if (sHalWrapper != nullptr) {
551 oldPowerHintSessionThreadIds = sHalWrapper->getPowerHintSessionThreadIds();
552 oldTargetWorkDuration = sHalWrapper->getTargetWorkDuration();
553 }
554
Dan Stoza9c051c02020-02-28 10:19:07 -0800555 // If we used to have a HAL, but it stopped responding, attempt to reconnect
Michael Wright1509a232018-06-21 02:50:34 +0100556 if (mReconnectPowerHal) {
Dan Stoza030fbc12020-02-19 15:32:01 -0800557 sHalWrapper = nullptr;
Michael Wright1509a232018-06-21 02:50:34 +0100558 mReconnectPowerHal = false;
559 }
560
Dan Stoza030fbc12020-02-19 15:32:01 -0800561 if (sHalWrapper != nullptr) {
Matt Buckley06f299a2021-09-24 19:43:51 +0000562 auto wrapper = sHalWrapper.get();
563 // if the wrapper is fine, return it, but if it indicates a reconnect, remake it
564 if (!wrapper->shouldReconnectHAL()) {
565 return wrapper;
566 }
567 sHalWrapper = nullptr;
Michael Wright1509a232018-06-21 02:50:34 +0100568 }
Dan Stoza030fbc12020-02-19 15:32:01 -0800569
Matt Buckley06f299a2021-09-24 19:43:51 +0000570 // at this point, we know for sure there is no running session
571 mPowerHintSessionRunning = false;
572
Dan Stoza030fbc12020-02-19 15:32:01 -0800573 // First attempt to connect to the AIDL Power HAL
574 sHalWrapper = AidlPowerHalWrapper::connect();
575
576 // If that didn't succeed, attempt to connect to the HIDL Power HAL
577 if (sHalWrapper == nullptr) {
578 sHalWrapper = HidlPowerHalWrapper::connect();
Matt Buckley06f299a2021-09-24 19:43:51 +0000579 } else { // if AIDL, pass on any existing hint session values
580 // thread ids always safe to set
581 sHalWrapper->setPowerHintSessionThreadIds(oldPowerHintSessionThreadIds);
582 // only set duration and start if duration is defined
583 if (oldTargetWorkDuration.has_value()) {
584 sHalWrapper->setTargetWorkDuration(*oldTargetWorkDuration);
585 // only start if possible to run and both threadids and duration are defined
586 if (usePowerHintSession() && !oldPowerHintSessionThreadIds.empty()) {
587 mPowerHintSessionRunning = sHalWrapper->startPowerHintSession();
588 }
589 }
Dan Stoza030fbc12020-02-19 15:32:01 -0800590 }
591
Dan Stoza9c051c02020-02-28 10:19:07 -0800592 // If we make it to this point and still don't have a HAL, it's unlikely we
593 // will, so stop trying
594 if (sHalWrapper == nullptr) {
595 sHasHal = false;
596 }
597
Dan Stoza030fbc12020-02-19 15:32:01 -0800598 return sHalWrapper.get();
Michael Wright1509a232018-06-21 02:50:34 +0100599}
600
601} // namespace impl
602} // namespace Hwc2
603} // namespace android