xref: /aosp_15_r20/frameworks/base/libs/hwui/renderthread/HintSessionWrapper.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker  * Copyright (C) 2022 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker  *
4*d57664e9SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*d57664e9SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*d57664e9SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*d57664e9SAndroid Build Coastguard Worker  *
8*d57664e9SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*d57664e9SAndroid Build Coastguard Worker  *
10*d57664e9SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*d57664e9SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*d57664e9SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d57664e9SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*d57664e9SAndroid Build Coastguard Worker  * limitations under the License.
15*d57664e9SAndroid Build Coastguard Worker  */
16*d57664e9SAndroid Build Coastguard Worker 
17*d57664e9SAndroid Build Coastguard Worker #include "HintSessionWrapper.h"
18*d57664e9SAndroid Build Coastguard Worker 
19*d57664e9SAndroid Build Coastguard Worker #include <dlfcn.h>
20*d57664e9SAndroid Build Coastguard Worker #include <private/performance_hint_private.h>
21*d57664e9SAndroid Build Coastguard Worker #include <utils/Log.h>
22*d57664e9SAndroid Build Coastguard Worker 
23*d57664e9SAndroid Build Coastguard Worker #include <algorithm>
24*d57664e9SAndroid Build Coastguard Worker #include <chrono>
25*d57664e9SAndroid Build Coastguard Worker #include <vector>
26*d57664e9SAndroid Build Coastguard Worker 
27*d57664e9SAndroid Build Coastguard Worker #include "../Properties.h"
28*d57664e9SAndroid Build Coastguard Worker #include "RenderThread.h"
29*d57664e9SAndroid Build Coastguard Worker #include "thread/CommonPool.h"
30*d57664e9SAndroid Build Coastguard Worker 
31*d57664e9SAndroid Build Coastguard Worker using namespace std::chrono_literals;
32*d57664e9SAndroid Build Coastguard Worker 
33*d57664e9SAndroid Build Coastguard Worker namespace android {
34*d57664e9SAndroid Build Coastguard Worker namespace uirenderer {
35*d57664e9SAndroid Build Coastguard Worker namespace renderthread {
36*d57664e9SAndroid Build Coastguard Worker 
37*d57664e9SAndroid Build Coastguard Worker #define BIND_APH_METHOD(name)                                         \
38*d57664e9SAndroid Build Coastguard Worker     name = (decltype(name))dlsym(handle_, "APerformanceHint_" #name); \
39*d57664e9SAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(name == nullptr, "Failed to find required symbol APerformanceHint_" #name)
40*d57664e9SAndroid Build Coastguard Worker 
init()41*d57664e9SAndroid Build Coastguard Worker void HintSessionWrapper::HintSessionBinding::init() {
42*d57664e9SAndroid Build Coastguard Worker     if (mInitialized) return;
43*d57664e9SAndroid Build Coastguard Worker 
44*d57664e9SAndroid Build Coastguard Worker     void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE);
45*d57664e9SAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(handle_ == nullptr, "Failed to dlopen libandroid.so!");
46*d57664e9SAndroid Build Coastguard Worker 
47*d57664e9SAndroid Build Coastguard Worker     BIND_APH_METHOD(getManager);
48*d57664e9SAndroid Build Coastguard Worker     BIND_APH_METHOD(createSessionInternal);
49*d57664e9SAndroid Build Coastguard Worker     BIND_APH_METHOD(closeSession);
50*d57664e9SAndroid Build Coastguard Worker     BIND_APH_METHOD(updateTargetWorkDuration);
51*d57664e9SAndroid Build Coastguard Worker     BIND_APH_METHOD(reportActualWorkDuration);
52*d57664e9SAndroid Build Coastguard Worker     BIND_APH_METHOD(sendHint);
53*d57664e9SAndroid Build Coastguard Worker     BIND_APH_METHOD(setThreads);
54*d57664e9SAndroid Build Coastguard Worker 
55*d57664e9SAndroid Build Coastguard Worker     mInitialized = true;
56*d57664e9SAndroid Build Coastguard Worker }
57*d57664e9SAndroid Build Coastguard Worker 
HintSessionWrapper(pid_t uiThreadId,pid_t renderThreadId)58*d57664e9SAndroid Build Coastguard Worker HintSessionWrapper::HintSessionWrapper(pid_t uiThreadId, pid_t renderThreadId)
59*d57664e9SAndroid Build Coastguard Worker         : mUiThreadId(uiThreadId)
60*d57664e9SAndroid Build Coastguard Worker         , mRenderThreadId(renderThreadId)
61*d57664e9SAndroid Build Coastguard Worker         , mBinding(std::make_shared<HintSessionBinding>()) {}
62*d57664e9SAndroid Build Coastguard Worker 
~HintSessionWrapper()63*d57664e9SAndroid Build Coastguard Worker HintSessionWrapper::~HintSessionWrapper() {
64*d57664e9SAndroid Build Coastguard Worker     destroy();
65*d57664e9SAndroid Build Coastguard Worker }
66*d57664e9SAndroid Build Coastguard Worker 
destroy()67*d57664e9SAndroid Build Coastguard Worker void HintSessionWrapper::destroy() {
68*d57664e9SAndroid Build Coastguard Worker     if (mHintSessionFuture.has_value()) {
69*d57664e9SAndroid Build Coastguard Worker         mHintSession = mHintSessionFuture->get();
70*d57664e9SAndroid Build Coastguard Worker         mHintSessionFuture = std::nullopt;
71*d57664e9SAndroid Build Coastguard Worker     }
72*d57664e9SAndroid Build Coastguard Worker     if (mSetThreadsFuture.has_value()) {
73*d57664e9SAndroid Build Coastguard Worker         mSetThreadsFuture->wait();
74*d57664e9SAndroid Build Coastguard Worker         mSetThreadsFuture = std::nullopt;
75*d57664e9SAndroid Build Coastguard Worker     }
76*d57664e9SAndroid Build Coastguard Worker     if (mHintSession) {
77*d57664e9SAndroid Build Coastguard Worker         mBinding->closeSession(mHintSession);
78*d57664e9SAndroid Build Coastguard Worker         mSessionValid = true;
79*d57664e9SAndroid Build Coastguard Worker         mHintSession = nullptr;
80*d57664e9SAndroid Build Coastguard Worker     }
81*d57664e9SAndroid Build Coastguard Worker     mResetsSinceLastReport = 0;
82*d57664e9SAndroid Build Coastguard Worker }
83*d57664e9SAndroid Build Coastguard Worker 
init()84*d57664e9SAndroid Build Coastguard Worker bool HintSessionWrapper::init() {
85*d57664e9SAndroid Build Coastguard Worker     if (mHintSession != nullptr) return true;
86*d57664e9SAndroid Build Coastguard Worker     // If we're waiting for the session
87*d57664e9SAndroid Build Coastguard Worker     if (mHintSessionFuture.has_value()) {
88*d57664e9SAndroid Build Coastguard Worker         // If the session is here
89*d57664e9SAndroid Build Coastguard Worker         if (mHintSessionFuture->wait_for(0s) == std::future_status::ready) {
90*d57664e9SAndroid Build Coastguard Worker             mHintSession = mHintSessionFuture->get();
91*d57664e9SAndroid Build Coastguard Worker             mHintSessionFuture = std::nullopt;
92*d57664e9SAndroid Build Coastguard Worker             if (mHintSession != nullptr) {
93*d57664e9SAndroid Build Coastguard Worker                 mSessionValid = true;
94*d57664e9SAndroid Build Coastguard Worker                 return true;
95*d57664e9SAndroid Build Coastguard Worker             }
96*d57664e9SAndroid Build Coastguard Worker         }
97*d57664e9SAndroid Build Coastguard Worker         return false;
98*d57664e9SAndroid Build Coastguard Worker     }
99*d57664e9SAndroid Build Coastguard Worker 
100*d57664e9SAndroid Build Coastguard Worker     // If it broke last time we tried this, shouldn't be running, or
101*d57664e9SAndroid Build Coastguard Worker     // has bad argument values, don't even bother
102*d57664e9SAndroid Build Coastguard Worker     if (!mSessionValid || !Properties::useHintManager || !Properties::isDrawingEnabled() ||
103*d57664e9SAndroid Build Coastguard Worker         mUiThreadId < 0 || mRenderThreadId < 0) {
104*d57664e9SAndroid Build Coastguard Worker         return false;
105*d57664e9SAndroid Build Coastguard Worker     }
106*d57664e9SAndroid Build Coastguard Worker 
107*d57664e9SAndroid Build Coastguard Worker     // Assume that if we return before the end, it broke
108*d57664e9SAndroid Build Coastguard Worker     mSessionValid = false;
109*d57664e9SAndroid Build Coastguard Worker 
110*d57664e9SAndroid Build Coastguard Worker     mBinding->init();
111*d57664e9SAndroid Build Coastguard Worker 
112*d57664e9SAndroid Build Coastguard Worker     APerformanceHintManager* manager = mBinding->getManager();
113*d57664e9SAndroid Build Coastguard Worker     if (!manager) return false;
114*d57664e9SAndroid Build Coastguard Worker 
115*d57664e9SAndroid Build Coastguard Worker     mPermanentSessionTids = CommonPool::getThreadIds();
116*d57664e9SAndroid Build Coastguard Worker     mPermanentSessionTids.push_back(mUiThreadId);
117*d57664e9SAndroid Build Coastguard Worker     mPermanentSessionTids.push_back(mRenderThreadId);
118*d57664e9SAndroid Build Coastguard Worker 
119*d57664e9SAndroid Build Coastguard Worker     // Use the cached target value if there is one, otherwise use a default. This is to ensure
120*d57664e9SAndroid Build Coastguard Worker     // the cached target and target in PowerHAL are consistent, and that it updates correctly
121*d57664e9SAndroid Build Coastguard Worker     // whenever there is a change.
122*d57664e9SAndroid Build Coastguard Worker     int64_t targetDurationNanos =
123*d57664e9SAndroid Build Coastguard Worker             mLastTargetWorkDuration == 0 ? kDefaultTargetDuration : mLastTargetWorkDuration;
124*d57664e9SAndroid Build Coastguard Worker     mHintSessionFuture = CommonPool::async([=, this, tids = mPermanentSessionTids] {
125*d57664e9SAndroid Build Coastguard Worker         return mBinding->createSessionInternal(manager, tids.data(), tids.size(),
126*d57664e9SAndroid Build Coastguard Worker                                                targetDurationNanos, SessionTag::HWUI);
127*d57664e9SAndroid Build Coastguard Worker     });
128*d57664e9SAndroid Build Coastguard Worker     return false;
129*d57664e9SAndroid Build Coastguard Worker }
130*d57664e9SAndroid Build Coastguard Worker 
updateTargetWorkDuration(long targetWorkDurationNanos)131*d57664e9SAndroid Build Coastguard Worker void HintSessionWrapper::updateTargetWorkDuration(long targetWorkDurationNanos) {
132*d57664e9SAndroid Build Coastguard Worker     if (!init()) return;
133*d57664e9SAndroid Build Coastguard Worker     targetWorkDurationNanos = targetWorkDurationNanos * Properties::targetCpuTimePercentage / 100;
134*d57664e9SAndroid Build Coastguard Worker     if (targetWorkDurationNanos != mLastTargetWorkDuration &&
135*d57664e9SAndroid Build Coastguard Worker         targetWorkDurationNanos > kSanityCheckLowerBound &&
136*d57664e9SAndroid Build Coastguard Worker         targetWorkDurationNanos < kSanityCheckUpperBound) {
137*d57664e9SAndroid Build Coastguard Worker         mLastTargetWorkDuration = targetWorkDurationNanos;
138*d57664e9SAndroid Build Coastguard Worker         mBinding->updateTargetWorkDuration(mHintSession, targetWorkDurationNanos);
139*d57664e9SAndroid Build Coastguard Worker     }
140*d57664e9SAndroid Build Coastguard Worker     mLastFrameNotification = systemTime();
141*d57664e9SAndroid Build Coastguard Worker }
142*d57664e9SAndroid Build Coastguard Worker 
reportActualWorkDuration(long actualDurationNanos)143*d57664e9SAndroid Build Coastguard Worker void HintSessionWrapper::reportActualWorkDuration(long actualDurationNanos) {
144*d57664e9SAndroid Build Coastguard Worker     if (!init()) return;
145*d57664e9SAndroid Build Coastguard Worker     mResetsSinceLastReport = 0;
146*d57664e9SAndroid Build Coastguard Worker     if (actualDurationNanos > kSanityCheckLowerBound &&
147*d57664e9SAndroid Build Coastguard Worker         actualDurationNanos < kSanityCheckUpperBound) {
148*d57664e9SAndroid Build Coastguard Worker         mBinding->reportActualWorkDuration(mHintSession, actualDurationNanos);
149*d57664e9SAndroid Build Coastguard Worker     }
150*d57664e9SAndroid Build Coastguard Worker     mLastFrameNotification = systemTime();
151*d57664e9SAndroid Build Coastguard Worker }
152*d57664e9SAndroid Build Coastguard Worker 
setActiveFunctorThreads(std::vector<pid_t> threadIds)153*d57664e9SAndroid Build Coastguard Worker void HintSessionWrapper::setActiveFunctorThreads(std::vector<pid_t> threadIds) {
154*d57664e9SAndroid Build Coastguard Worker     if (!init()) return;
155*d57664e9SAndroid Build Coastguard Worker     if (!mBinding || !mHintSession) return;
156*d57664e9SAndroid Build Coastguard Worker     // Sort the vector to make sure they're compared as sets.
157*d57664e9SAndroid Build Coastguard Worker     std::sort(threadIds.begin(), threadIds.end());
158*d57664e9SAndroid Build Coastguard Worker     if (threadIds == mActiveFunctorTids) return;
159*d57664e9SAndroid Build Coastguard Worker     mActiveFunctorTids = std::move(threadIds);
160*d57664e9SAndroid Build Coastguard Worker     std::vector<pid_t> combinedTids = mPermanentSessionTids;
161*d57664e9SAndroid Build Coastguard Worker     std::copy(mActiveFunctorTids.begin(), mActiveFunctorTids.end(),
162*d57664e9SAndroid Build Coastguard Worker               std::back_inserter(combinedTids));
163*d57664e9SAndroid Build Coastguard Worker     mSetThreadsFuture = CommonPool::async([this, tids = std::move(combinedTids)] {
164*d57664e9SAndroid Build Coastguard Worker         int ret = mBinding->setThreads(mHintSession, tids.data(), tids.size());
165*d57664e9SAndroid Build Coastguard Worker         ALOGE_IF(ret != 0, "APerformaceHint_setThreads failed: %d", ret);
166*d57664e9SAndroid Build Coastguard Worker         return ret;
167*d57664e9SAndroid Build Coastguard Worker     });
168*d57664e9SAndroid Build Coastguard Worker }
169*d57664e9SAndroid Build Coastguard Worker 
sendLoadResetHint()170*d57664e9SAndroid Build Coastguard Worker void HintSessionWrapper::sendLoadResetHint() {
171*d57664e9SAndroid Build Coastguard Worker     static constexpr int kMaxResetsSinceLastReport = 2;
172*d57664e9SAndroid Build Coastguard Worker     if (!init()) return;
173*d57664e9SAndroid Build Coastguard Worker     nsecs_t now = systemTime();
174*d57664e9SAndroid Build Coastguard Worker     if (now - mLastFrameNotification > kResetHintTimeout &&
175*d57664e9SAndroid Build Coastguard Worker         mResetsSinceLastReport <= kMaxResetsSinceLastReport) {
176*d57664e9SAndroid Build Coastguard Worker         ++mResetsSinceLastReport;
177*d57664e9SAndroid Build Coastguard Worker         mBinding->sendHint(mHintSession, static_cast<int32_t>(SessionHint::CPU_LOAD_RESET));
178*d57664e9SAndroid Build Coastguard Worker     }
179*d57664e9SAndroid Build Coastguard Worker     mLastFrameNotification = now;
180*d57664e9SAndroid Build Coastguard Worker }
181*d57664e9SAndroid Build Coastguard Worker 
sendLoadIncreaseHint()182*d57664e9SAndroid Build Coastguard Worker void HintSessionWrapper::sendLoadIncreaseHint() {
183*d57664e9SAndroid Build Coastguard Worker     if (!init()) return;
184*d57664e9SAndroid Build Coastguard Worker     mBinding->sendHint(mHintSession, static_cast<int32_t>(SessionHint::CPU_LOAD_UP));
185*d57664e9SAndroid Build Coastguard Worker }
186*d57664e9SAndroid Build Coastguard Worker 
alive()187*d57664e9SAndroid Build Coastguard Worker bool HintSessionWrapper::alive() {
188*d57664e9SAndroid Build Coastguard Worker     return mHintSession != nullptr;
189*d57664e9SAndroid Build Coastguard Worker }
190*d57664e9SAndroid Build Coastguard Worker 
getLastUpdate()191*d57664e9SAndroid Build Coastguard Worker nsecs_t HintSessionWrapper::getLastUpdate() {
192*d57664e9SAndroid Build Coastguard Worker     return mLastFrameNotification;
193*d57664e9SAndroid Build Coastguard Worker }
194*d57664e9SAndroid Build Coastguard Worker 
195*d57664e9SAndroid Build Coastguard Worker // Requires passing in its shared_ptr since it shouldn't own a shared_ptr to itself
delayedDestroy(RenderThread & rt,nsecs_t delay,std::shared_ptr<HintSessionWrapper> wrapperPtr)196*d57664e9SAndroid Build Coastguard Worker void HintSessionWrapper::delayedDestroy(RenderThread& rt, nsecs_t delay,
197*d57664e9SAndroid Build Coastguard Worker                                         std::shared_ptr<HintSessionWrapper> wrapperPtr) {
198*d57664e9SAndroid Build Coastguard Worker     nsecs_t lastUpdate = wrapperPtr->getLastUpdate();
199*d57664e9SAndroid Build Coastguard Worker     rt.queue().postDelayed(delay, [lastUpdate = lastUpdate, wrapper = wrapperPtr]() mutable {
200*d57664e9SAndroid Build Coastguard Worker         if (wrapper->getLastUpdate() == lastUpdate) {
201*d57664e9SAndroid Build Coastguard Worker             wrapper->destroy();
202*d57664e9SAndroid Build Coastguard Worker         }
203*d57664e9SAndroid Build Coastguard Worker         // Ensure the shared_ptr is killed at the end of the method
204*d57664e9SAndroid Build Coastguard Worker         wrapper = nullptr;
205*d57664e9SAndroid Build Coastguard Worker     });
206*d57664e9SAndroid Build Coastguard Worker }
207*d57664e9SAndroid Build Coastguard Worker 
208*d57664e9SAndroid Build Coastguard Worker } /* namespace renderthread */
209*d57664e9SAndroid Build Coastguard Worker } /* namespace uirenderer */
210*d57664e9SAndroid Build Coastguard Worker } /* namespace android */
211