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