blob: edacef04b50a61609dae101a91e9afa3175c86ec [file] [log] [blame]
Matt Buckleye9023cf2022-11-23 22:39:25 +00001/*
2 * Copyright (C) 2022 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
17#include "HintSessionWrapper.h"
18
19#include <dlfcn.h>
20#include <utils/Log.h>
21
22#include <vector>
23
24#include "../Properties.h"
25#include "thread/CommonPool.h"
26
27namespace android {
28namespace uirenderer {
29namespace renderthread {
30
31namespace {
32
33typedef APerformanceHintManager* (*APH_getManager)();
34typedef APerformanceHintSession* (*APH_createSession)(APerformanceHintManager*, const int32_t*,
35 size_t, int64_t);
36typedef void (*APH_closeSession)(APerformanceHintSession* session);
37typedef void (*APH_updateTargetWorkDuration)(APerformanceHintSession*, int64_t);
38typedef void (*APH_reportActualWorkDuration)(APerformanceHintSession*, int64_t);
39typedef void (*APH_sendHint)(APerformanceHintSession* session, int32_t);
40
41bool gAPerformanceHintBindingInitialized = false;
42APH_getManager gAPH_getManagerFn = nullptr;
43APH_createSession gAPH_createSessionFn = nullptr;
44APH_closeSession gAPH_closeSessionFn = nullptr;
45APH_updateTargetWorkDuration gAPH_updateTargetWorkDurationFn = nullptr;
46APH_reportActualWorkDuration gAPH_reportActualWorkDurationFn = nullptr;
47APH_sendHint gAPH_sendHintFn = nullptr;
48
49void ensureAPerformanceHintBindingInitialized() {
50 if (gAPerformanceHintBindingInitialized) return;
51
52 void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE);
53 LOG_ALWAYS_FATAL_IF(handle_ == nullptr, "Failed to dlopen libandroid.so!");
54
55 gAPH_getManagerFn = (APH_getManager)dlsym(handle_, "APerformanceHint_getManager");
56 LOG_ALWAYS_FATAL_IF(gAPH_getManagerFn == nullptr,
57 "Failed to find required symbol APerformanceHint_getManager!");
58
59 gAPH_createSessionFn = (APH_createSession)dlsym(handle_, "APerformanceHint_createSession");
60 LOG_ALWAYS_FATAL_IF(gAPH_createSessionFn == nullptr,
61 "Failed to find required symbol APerformanceHint_createSession!");
62
63 gAPH_closeSessionFn = (APH_closeSession)dlsym(handle_, "APerformanceHint_closeSession");
64 LOG_ALWAYS_FATAL_IF(gAPH_closeSessionFn == nullptr,
65 "Failed to find required symbol APerformanceHint_closeSession!");
66
67 gAPH_updateTargetWorkDurationFn = (APH_updateTargetWorkDuration)dlsym(
68 handle_, "APerformanceHint_updateTargetWorkDuration");
69 LOG_ALWAYS_FATAL_IF(
70 gAPH_updateTargetWorkDurationFn == nullptr,
71 "Failed to find required symbol APerformanceHint_updateTargetWorkDuration!");
72
73 gAPH_reportActualWorkDurationFn = (APH_reportActualWorkDuration)dlsym(
74 handle_, "APerformanceHint_reportActualWorkDuration");
75 LOG_ALWAYS_FATAL_IF(
76 gAPH_reportActualWorkDurationFn == nullptr,
77 "Failed to find required symbol APerformanceHint_reportActualWorkDuration!");
78
79 gAPH_sendHintFn = (APH_sendHint)dlsym(handle_, "APerformanceHint_sendHint");
80 LOG_ALWAYS_FATAL_IF(gAPH_sendHintFn == nullptr,
81 "Failed to find required symbol APerformanceHint_sendHint!");
82
83 gAPerformanceHintBindingInitialized = true;
84}
85
86} // namespace
87
88HintSessionWrapper::HintSessionWrapper(pid_t uiThreadId, pid_t renderThreadId)
89 : mUiThreadId(uiThreadId), mRenderThreadId(renderThreadId) {}
90
91HintSessionWrapper::~HintSessionWrapper() {
92 if (mHintSession) {
93 gAPH_closeSessionFn(mHintSession);
94 }
95}
96
97bool HintSessionWrapper::useHintSession() {
98 if (!Properties::useHintManager || !Properties::isDrawingEnabled()) return false;
99 if (mHintSession) return true;
100 // If session does not exist, create it;
101 // this defers session creation until we try to actually use it.
102 if (!mSessionValid) return false;
103 return init();
104}
105
106bool HintSessionWrapper::init() {
107 if (mUiThreadId < 0 || mRenderThreadId < 0) return false;
108
109 // Assume that if we return before the end, it broke
110 mSessionValid = false;
111
112 ensureAPerformanceHintBindingInitialized();
113
114 APerformanceHintManager* manager = gAPH_getManagerFn();
115 if (!manager) return false;
116
117 std::vector<pid_t> tids = CommonPool::getThreadIds();
118 tids.push_back(mUiThreadId);
119 tids.push_back(mRenderThreadId);
120
121 // Use a placeholder target value to initialize,
122 // this will always be replaced elsewhere before it gets used
123 int64_t defaultTargetDurationNanos = 16666667;
124 mHintSession =
125 gAPH_createSessionFn(manager, tids.data(), tids.size(), defaultTargetDurationNanos);
126
127 mSessionValid = !!mHintSession;
128 return mSessionValid;
129}
130
131void HintSessionWrapper::updateTargetWorkDuration(long targetWorkDurationNanos) {
132 if (!useHintSession()) return;
133 targetWorkDurationNanos = targetWorkDurationNanos * Properties::targetCpuTimePercentage / 100;
134 if (targetWorkDurationNanos != mLastTargetWorkDuration &&
135 targetWorkDurationNanos > kSanityCheckLowerBound &&
136 targetWorkDurationNanos < kSanityCheckUpperBound) {
137 mLastTargetWorkDuration = targetWorkDurationNanos;
138 gAPH_updateTargetWorkDurationFn(mHintSession, targetWorkDurationNanos);
139 }
140 mLastFrameNotification = systemTime();
141}
142
143void HintSessionWrapper::reportActualWorkDuration(long actualDurationNanos) {
144 if (!useHintSession()) return;
145 if (actualDurationNanos > kSanityCheckLowerBound &&
146 actualDurationNanos < kSanityCheckUpperBound) {
147 gAPH_reportActualWorkDurationFn(mHintSession, actualDurationNanos);
148 }
149}
150
151void HintSessionWrapper::sendLoadResetHint() {
152 if (!useHintSession()) return;
153 nsecs_t now = systemTime();
154 if (now - mLastFrameNotification > kResetHintTimeout) {
155 gAPH_sendHintFn(mHintSession, static_cast<int>(SessionHint::CPU_LOAD_RESET));
156 }
157 mLastFrameNotification = now;
158}
159
160} /* namespace renderthread */
161} /* namespace uirenderer */
162} /* namespace android */