blob: 8c9f65fac10c457df316a348c3512ac539f0a417 [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
Matt Buckleye9023cf2022-11-23 22:39:25 +000098bool HintSessionWrapper::init() {
Matt Buckley124d0c672023-01-19 03:04:19 +000099 // If it already exists, broke last time we tried this, shouldn't be running, or
100 // has bad argument values, don't even bother
101 if (mHintSession != nullptr || !mSessionValid || !Properties::useHintManager ||
102 !Properties::isDrawingEnabled() || mUiThreadId < 0 || mRenderThreadId < 0) {
103 return false;
104 }
Matt Buckleye9023cf2022-11-23 22:39:25 +0000105
106 // Assume that if we return before the end, it broke
107 mSessionValid = false;
108
109 ensureAPerformanceHintBindingInitialized();
110
111 APerformanceHintManager* manager = gAPH_getManagerFn();
112 if (!manager) return false;
113
114 std::vector<pid_t> tids = CommonPool::getThreadIds();
115 tids.push_back(mUiThreadId);
116 tids.push_back(mRenderThreadId);
117
118 // Use a placeholder target value to initialize,
119 // this will always be replaced elsewhere before it gets used
120 int64_t defaultTargetDurationNanos = 16666667;
121 mHintSession =
122 gAPH_createSessionFn(manager, tids.data(), tids.size(), defaultTargetDurationNanos);
123
124 mSessionValid = !!mHintSession;
125 return mSessionValid;
126}
127
128void HintSessionWrapper::updateTargetWorkDuration(long targetWorkDurationNanos) {
Matt Buckley124d0c672023-01-19 03:04:19 +0000129 if (mHintSession == nullptr) return;
Matt Buckleye9023cf2022-11-23 22:39:25 +0000130 targetWorkDurationNanos = targetWorkDurationNanos * Properties::targetCpuTimePercentage / 100;
131 if (targetWorkDurationNanos != mLastTargetWorkDuration &&
132 targetWorkDurationNanos > kSanityCheckLowerBound &&
133 targetWorkDurationNanos < kSanityCheckUpperBound) {
134 mLastTargetWorkDuration = targetWorkDurationNanos;
135 gAPH_updateTargetWorkDurationFn(mHintSession, targetWorkDurationNanos);
136 }
137 mLastFrameNotification = systemTime();
138}
139
140void HintSessionWrapper::reportActualWorkDuration(long actualDurationNanos) {
Matt Buckley124d0c672023-01-19 03:04:19 +0000141 if (mHintSession == nullptr) return;
Matt Buckleye9023cf2022-11-23 22:39:25 +0000142 if (actualDurationNanos > kSanityCheckLowerBound &&
143 actualDurationNanos < kSanityCheckUpperBound) {
144 gAPH_reportActualWorkDurationFn(mHintSession, actualDurationNanos);
145 }
146}
147
148void HintSessionWrapper::sendLoadResetHint() {
Matt Buckley124d0c672023-01-19 03:04:19 +0000149 if (mHintSession == nullptr) return;
Matt Buckleye9023cf2022-11-23 22:39:25 +0000150 nsecs_t now = systemTime();
151 if (now - mLastFrameNotification > kResetHintTimeout) {
152 gAPH_sendHintFn(mHintSession, static_cast<int>(SessionHint::CPU_LOAD_RESET));
153 }
154 mLastFrameNotification = now;
155}
156
Matt Buckleyac5f7552022-12-19 22:03:27 +0000157void HintSessionWrapper::sendLoadIncreaseHint() {
Matt Buckley124d0c672023-01-19 03:04:19 +0000158 if (mHintSession == nullptr) return;
Matt Buckleyac5f7552022-12-19 22:03:27 +0000159 gAPH_sendHintFn(mHintSession, static_cast<int>(SessionHint::CPU_LOAD_UP));
160}
161
Matt Buckleye9023cf2022-11-23 22:39:25 +0000162} /* namespace renderthread */
163} /* namespace uirenderer */
164} /* namespace android */