1 /*
2 * Copyright (C) 2021 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 #define LOG_TAG "perf_hint"
18
19 #include <aidl/android/hardware/power/ChannelConfig.h>
20 #include <aidl/android/hardware/power/ChannelMessage.h>
21 #include <aidl/android/hardware/power/SessionConfig.h>
22 #include <aidl/android/hardware/power/SessionHint.h>
23 #include <aidl/android/hardware/power/SessionMode.h>
24 #include <aidl/android/hardware/power/SessionTag.h>
25 #include <aidl/android/hardware/power/WorkDuration.h>
26 #include <aidl/android/hardware/power/WorkDurationFixedV1.h>
27 #include <aidl/android/os/IHintManager.h>
28 #include <aidl/android/os/IHintSession.h>
29 #include <aidl/android/os/SessionCreationConfig.h>
30 #include <android-base/stringprintf.h>
31 #include <android-base/thread_annotations.h>
32 #include <android/binder_libbinder.h>
33 #include <android/binder_manager.h>
34 #include <android/binder_status.h>
35 #include <android/native_window.h>
36 #include <android/performance_hint.h>
37 #include <android/surface_control.h>
38 #include <android/trace.h>
39 #include <android_os.h>
40 #include <cutils/trace.h>
41 #include <fmq/AidlMessageQueue.h>
42 #include <gui/Surface.h>
43 #include <gui/SurfaceComposerClient.h>
44 #include <gui/SurfaceControl.h>
45 #include <inttypes.h>
46 #include <jni_wrappers.h>
47 #include <performance_hint_private.h>
48 #include <utils/SystemClock.h>
49
50 #include <chrono>
51 #include <format>
52 #include <future>
53 #include <set>
54 #include <utility>
55 #include <vector>
56
57 using namespace android;
58 using namespace aidl::android::os;
59
60 using namespace std::chrono_literals;
61
62 // Namespace for AIDL types coming from the PowerHAL
63 namespace hal = aidl::android::hardware::power;
64
65 using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
66 using HalChannelMessageContents = hal::ChannelMessage::ChannelMessageContents;
67 using HalMessageQueue = ::android::AidlMessageQueue<hal::ChannelMessage, SynchronizedReadWrite>;
68 using HalFlagQueue = ::android::AidlMessageQueue<int8_t, SynchronizedReadWrite>;
69 using android::base::StringPrintf;
70
71 struct APerformanceHintSession;
72
73 constexpr int64_t SEND_HINT_TIMEOUT = std::chrono::nanoseconds(100ms).count();
74 struct AWorkDuration : public hal::WorkDuration {};
75 struct ASessionCreationConfig : public SessionCreationConfig {
76 std::vector<wp<IBinder>> layers{};
hasModeASessionCreationConfig77 bool hasMode(hal::SessionMode&& mode) {
78 return std::find(modesToEnable.begin(), modesToEnable.end(), mode) != modesToEnable.end();
79 }
80 };
81
82 bool kForceGraphicsPipeline = false;
83
useGraphicsPipeline()84 bool useGraphicsPipeline() {
85 return android::os::adpf_graphics_pipeline() || kForceGraphicsPipeline;
86 }
87
88 // A pair of values that determine the behavior of the
89 // load hint rate limiter, to only allow "X hints every Y seconds"
90 constexpr double kLoadHintInterval = std::chrono::nanoseconds(2s).count();
91 constexpr double kMaxLoadHintsPerInterval = 20;
92 constexpr double kReplenishRate = kMaxLoadHintsPerInterval / kLoadHintInterval;
93 bool kForceNewHintBehavior = false;
94
95 template <class T>
enum_size()96 constexpr int32_t enum_size() {
97 return static_cast<int32_t>(*(ndk::enum_range<T>().end() - 1)) + 1;
98 }
99
useNewLoadHintBehavior()100 bool useNewLoadHintBehavior() {
101 return android::os::adpf_use_load_hints() || kForceNewHintBehavior;
102 }
103
104 // Shared lock for the whole PerformanceHintManager and sessions
105 static std::mutex sHintMutex = std::mutex{};
106 class FMQWrapper {
107 public:
108 bool isActive();
109 bool isSupported();
110 bool startChannel(IHintManager* manager);
111 void stopChannel(IHintManager* manager);
112 // Number of elements the FMQ can hold
113 bool reportActualWorkDurations(std::optional<hal::SessionConfig>& config,
114 hal::WorkDuration* durations, size_t count) REQUIRES(sHintMutex);
115 bool updateTargetWorkDuration(std::optional<hal::SessionConfig>& config,
116 int64_t targetDurationNanos) REQUIRES(sHintMutex);
117 bool sendHints(std::optional<hal::SessionConfig>& config, std::vector<hal::SessionHint>& hint,
118 int64_t now) REQUIRES(sHintMutex);
119 bool setMode(std::optional<hal::SessionConfig>& config, hal::SessionMode, bool enabled)
120 REQUIRES(sHintMutex);
121 void setToken(ndk::SpAIBinder& token);
122 void attemptWake();
123 void setUnsupported();
124
125 private:
126 template <HalChannelMessageContents::Tag T, bool urgent = false,
127 class C = HalChannelMessageContents::_at<T>>
128 bool sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count = 1,
129 int64_t now = ::android::uptimeNanos()) REQUIRES(sHintMutex);
130 template <HalChannelMessageContents::Tag T, class C = HalChannelMessageContents::_at<T>>
131 void writeBuffer(C* message, hal::SessionConfig& config, size_t count, int64_t now)
132 REQUIRES(sHintMutex);
133
134 bool isActiveLocked() REQUIRES(sHintMutex);
135 bool updatePersistentTransaction() REQUIRES(sHintMutex);
136 std::shared_ptr<HalMessageQueue> mQueue GUARDED_BY(sHintMutex) = nullptr;
137 std::shared_ptr<HalFlagQueue> mFlagQueue GUARDED_BY(sHintMutex) = nullptr;
138 // android::hardware::EventFlag* mEventFlag GUARDED_BY(sHintMutex) = nullptr;
139 android::hardware::EventFlag* mEventFlag = nullptr;
140 int32_t mWriteMask;
141 ndk::SpAIBinder mToken = nullptr;
142 // Used to track if operating on the fmq consistently fails
143 bool mCorrupted = false;
144 // Used to keep a persistent transaction open with FMQ to reduce latency a bit
145 size_t mAvailableSlots GUARDED_BY(sHintMutex) = 0;
146 bool mHalSupported = true;
147 HalMessageQueue::MemTransaction mFmqTransaction GUARDED_BY(sHintMutex);
148 std::future<bool> mChannelCreationFinished;
149 };
150
151 struct APerformanceHintManager {
152 public:
153 static APerformanceHintManager* getInstance();
154 APerformanceHintManager(std::shared_ptr<IHintManager>& service, int64_t preferredRateNanos);
155 APerformanceHintManager() = delete;
156 ~APerformanceHintManager();
157
158 APerformanceHintSession* createSession(const int32_t* threadIds, size_t size,
159 int64_t initialTargetWorkDurationNanos,
160 hal::SessionTag tag = hal::SessionTag::APP,
161 bool isJava = false);
162 APerformanceHintSession* getSessionFromJava(JNIEnv* _Nonnull env, jobject _Nonnull sessionObj);
163
164 APerformanceHintSession* createSessionUsingConfig(ASessionCreationConfig* sessionCreationConfig,
165 hal::SessionTag tag = hal::SessionTag::APP,
166 bool isJava = false);
167 int64_t getPreferredRateNanos() const;
168 int32_t getMaxGraphicsPipelineThreadsCount();
169 FMQWrapper& getFMQWrapper();
170 bool canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) REQUIRES(sHintMutex);
171 void initJava(JNIEnv* _Nonnull env);
172 ndk::ScopedAIBinder_Weak x;
173 template <class T>
174 static void layersFromNativeSurfaces(ANativeWindow** windows, int numWindows,
175 ASurfaceControl** controls, int numSurfaceControls,
176 std::vector<T>& out);
177
178 private:
179 // Necessary to create an empty binder object
tokenStubOnCreateAPerformanceHintManager180 static void* tokenStubOnCreate(void*) {
181 return nullptr;
182 }
tokenStubOnDestroyAPerformanceHintManager183 static void tokenStubOnDestroy(void*) {}
tokenStubOnTransactAPerformanceHintManager184 static binder_status_t tokenStubOnTransact(AIBinder*, transaction_code_t, const AParcel*,
185 AParcel*) {
186 return STATUS_OK;
187 }
188
189 static APerformanceHintManager* create(std::shared_ptr<IHintManager> iHintManager);
190
191 std::shared_ptr<IHintManager> mHintManager;
192 ndk::SpAIBinder mToken;
193 const int64_t mPreferredRateNanos;
194 std::optional<int32_t> mMaxGraphicsPipelineThreadsCount;
195 FMQWrapper mFMQWrapper;
196 double mHintBudget = kMaxLoadHintsPerInterval;
197 int64_t mLastBudgetReplenish = 0;
198 bool mJavaInitialized = false;
199 jclass mJavaSessionClazz;
200 jfieldID mJavaSessionNativePtr;
201 };
202
203 struct APerformanceHintSession {
204 public:
205 APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
206 std::shared_ptr<IHintSession> session, int64_t preferredRateNanos,
207 int64_t targetDurationNanos, bool isJava,
208 std::optional<hal::SessionConfig> sessionConfig);
209 APerformanceHintSession() = delete;
210 ~APerformanceHintSession();
211
212 int updateTargetWorkDuration(int64_t targetDurationNanos);
213 int reportActualWorkDuration(int64_t actualDurationNanos);
214 int sendHints(std::vector<hal::SessionHint>& hints, int64_t now, const char* debugName);
215 int notifyWorkloadIncrease(bool cpu, bool gpu, const char* debugName);
216 int notifyWorkloadReset(bool cpu, bool gpu, const char* debugName);
217 int notifyWorkloadSpike(bool cpu, bool gpu, const char* debugName);
218 int setThreads(const int32_t* threadIds, size_t size);
219 int getThreadIds(int32_t* const threadIds, size_t* size);
220 int setPreferPowerEfficiency(bool enabled);
221 int reportActualWorkDuration(AWorkDuration* workDuration);
222 bool isJava();
223 status_t setNativeSurfaces(ANativeWindow** windows, int numWindows, ASurfaceControl** controls,
224 int numSurfaceControls);
225
226 private:
227 friend struct APerformanceHintManager;
228
229 int reportActualWorkDurationInternal(AWorkDuration* workDuration);
230
231 std::shared_ptr<IHintManager> mHintManager;
232 std::shared_ptr<IHintSession> mHintSession;
233 // HAL preferred update rate
234 const int64_t mPreferredRateNanos;
235 // Target duration for choosing update rate
236 int64_t mTargetDurationNanos GUARDED_BY(sHintMutex);
237 // First target hit timestamp
238 int64_t mFirstTargetMetTimestamp GUARDED_BY(sHintMutex);
239 // Last target hit timestamp
240 int64_t mLastTargetMetTimestamp GUARDED_BY(sHintMutex);
241 // Last hint reported from sendHint indexed by hint value
242 // This is only used by the old rate limiter impl and is replaced
243 // with the new rate limiter under a flag
244 std::vector<int64_t> mLastHintSentTimestamp GUARDED_BY(sHintMutex);
245 // Cached samples
246 std::vector<hal::WorkDuration> mActualWorkDurations GUARDED_BY(sHintMutex);
247 // Is this session backing an SDK wrapper object
248 const bool mIsJava;
249 std::string mSessionName;
250 static int64_t sIDCounter GUARDED_BY(sHintMutex);
251 // The most recent set of thread IDs
252 std::vector<int32_t> mLastThreadIDs GUARDED_BY(sHintMutex);
253 std::optional<hal::SessionConfig> mSessionConfig;
254 // Tracing helpers
255 void traceThreads(const std::vector<int32_t>& tids) REQUIRES(sHintMutex);
256 void tracePowerEfficient(bool powerEfficient);
257 void traceGraphicsPipeline(bool graphicsPipeline);
258 void traceModes(const std::vector<hal::SessionMode>& modesToEnable);
259 void traceActualDuration(int64_t actualDuration);
260 void traceBatchSize(size_t batchSize);
261 void traceTargetDuration(int64_t targetDuration);
262 };
263
264 static std::shared_ptr<IHintManager>* gIHintManagerForTesting = nullptr;
265 static std::shared_ptr<APerformanceHintManager> gHintManagerForTesting = nullptr;
266
267 static std::optional<bool> gForceFMQEnabled = std::nullopt;
268
269 // Start above the int32 range so we don't collide with config sessions
270 int64_t APerformanceHintSession::sIDCounter = INT32_MAX;
271
getFMQ()272 static FMQWrapper& getFMQ() {
273 return APerformanceHintManager::getInstance()->getFMQWrapper();
274 }
275
276 // ===================================== APerformanceHintManager implementation
APerformanceHintManager(std::shared_ptr<IHintManager> & manager,int64_t preferredRateNanos)277 APerformanceHintManager::APerformanceHintManager(std::shared_ptr<IHintManager>& manager,
278 int64_t preferredRateNanos)
279 : mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) {
280 static AIBinder_Class* tokenBinderClass =
281 AIBinder_Class_define("phm_token", tokenStubOnCreate, tokenStubOnDestroy,
282 tokenStubOnTransact);
283 mToken = ndk::SpAIBinder(AIBinder_new(tokenBinderClass, nullptr));
284 if (mFMQWrapper.isSupported()) {
285 mFMQWrapper.setToken(mToken);
286 mFMQWrapper.startChannel(mHintManager.get());
287 }
288 }
289
~APerformanceHintManager()290 APerformanceHintManager::~APerformanceHintManager() {
291 mFMQWrapper.stopChannel(mHintManager.get());
292 }
293
getInstance()294 APerformanceHintManager* APerformanceHintManager::getInstance() {
295 static std::once_flag creationFlag;
296 static APerformanceHintManager* instance = nullptr;
297 if (gHintManagerForTesting) {
298 return gHintManagerForTesting.get();
299 }
300 if (gIHintManagerForTesting) {
301 gHintManagerForTesting =
302 std::shared_ptr<APerformanceHintManager>(create(*gIHintManagerForTesting));
303 return gHintManagerForTesting.get();
304 }
305 std::call_once(creationFlag, []() { instance = create(nullptr); });
306 return instance;
307 }
308
create(std::shared_ptr<IHintManager> manager)309 APerformanceHintManager* APerformanceHintManager::create(std::shared_ptr<IHintManager> manager) {
310 if (!manager) {
311 manager = IHintManager::fromBinder(
312 ndk::SpAIBinder(AServiceManager_waitForService("performance_hint")));
313 }
314 if (manager == nullptr) {
315 ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__);
316 return nullptr;
317 }
318 int64_t preferredRateNanos = -1L;
319 ndk::ScopedAStatus ret = manager->getHintSessionPreferredRate(&preferredRateNanos);
320 if (!ret.isOk()) {
321 ALOGE("%s: PerformanceHint cannot get preferred rate. %s", __FUNCTION__, ret.getMessage());
322 return nullptr;
323 }
324 if (preferredRateNanos <= 0) {
325 preferredRateNanos = -1L;
326 }
327 return new APerformanceHintManager(manager, preferredRateNanos);
328 }
329
canSendLoadHints(std::vector<hal::SessionHint> & hints,int64_t now)330 bool APerformanceHintManager::canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) {
331 mHintBudget =
332 std::min(kMaxLoadHintsPerInterval,
333 mHintBudget +
334 static_cast<double>(now - mLastBudgetReplenish) * kReplenishRate);
335 mLastBudgetReplenish = now;
336
337 // If this youngest timestamp isn't older than the timeout time, we can't send
338 if (hints.size() > mHintBudget) {
339 return false;
340 }
341 mHintBudget -= hints.size();
342 return true;
343 }
344
createSession(const int32_t * threadIds,size_t size,int64_t initialTargetWorkDurationNanos,hal::SessionTag tag,bool isJava)345 APerformanceHintSession* APerformanceHintManager::createSession(
346 const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos,
347 hal::SessionTag tag, bool isJava) {
348 ndk::ScopedAStatus ret;
349 hal::SessionConfig sessionConfig{.id = -1};
350
351 ASessionCreationConfig creationConfig{{
352 .tids = std::vector<int32_t>(threadIds, threadIds + size),
353 .targetWorkDurationNanos = initialTargetWorkDurationNanos,
354 }};
355
356 return APerformanceHintManager::createSessionUsingConfig(&creationConfig, tag, isJava);
357 }
358
createSessionUsingConfig(ASessionCreationConfig * sessionCreationConfig,hal::SessionTag tag,bool isJava)359 APerformanceHintSession* APerformanceHintManager::createSessionUsingConfig(
360 ASessionCreationConfig* sessionCreationConfig, hal::SessionTag tag, bool isJava) {
361 std::shared_ptr<IHintSession> session;
362 hal::SessionConfig sessionConfig{.id = -1};
363 ndk::ScopedAStatus ret;
364
365 // Hold the tokens weakly until we actually need them,
366 // then promote them, then drop all strong refs after
367 if (!sessionCreationConfig->layers.empty()) {
368 for (auto&& layerIter = sessionCreationConfig->layers.begin();
369 layerIter != sessionCreationConfig->layers.end();) {
370 sp<IBinder> promoted = layerIter->promote();
371 if (promoted == nullptr) {
372 layerIter = sessionCreationConfig->layers.erase(layerIter);
373 } else {
374 sessionCreationConfig->layerTokens.push_back(
375 ndk::SpAIBinder(AIBinder_fromPlatformBinder(promoted.get())));
376 ++layerIter;
377 }
378 }
379 }
380
381 ret = mHintManager->createHintSessionWithConfig(mToken, tag,
382 *static_cast<SessionCreationConfig*>(
383 sessionCreationConfig),
384 &sessionConfig, &session);
385
386 sessionCreationConfig->layerTokens.clear();
387
388 if (!ret.isOk() || !session) {
389 ALOGE("%s: PerformanceHint cannot create session. %s", __FUNCTION__, ret.getMessage());
390 return nullptr;
391 }
392 auto out = new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos,
393 sessionCreationConfig->targetWorkDurationNanos, isJava,
394 sessionConfig.id == -1
395 ? std::nullopt
396 : std::make_optional<hal::SessionConfig>(
397 std::move(sessionConfig)));
398 std::scoped_lock lock(sHintMutex);
399 out->traceThreads(sessionCreationConfig->tids);
400 out->traceTargetDuration(sessionCreationConfig->targetWorkDurationNanos);
401 out->traceModes(sessionCreationConfig->modesToEnable);
402
403 return out;
404 }
405
getSessionFromJava(JNIEnv * env,jobject sessionObj)406 APerformanceHintSession* APerformanceHintManager::getSessionFromJava(JNIEnv* env,
407 jobject sessionObj) {
408 initJava(env);
409 LOG_ALWAYS_FATAL_IF(!env->IsInstanceOf(sessionObj, mJavaSessionClazz),
410 "Wrong java type passed to APerformanceHint_getSessionFromJava");
411 APerformanceHintSession* out = reinterpret_cast<APerformanceHintSession*>(
412 env->GetLongField(sessionObj, mJavaSessionNativePtr));
413 LOG_ALWAYS_FATAL_IF(out == nullptr, "Java-wrapped native hint session is nullptr");
414 LOG_ALWAYS_FATAL_IF(!out->isJava(), "Unmanaged native hint session returned from Java SDK");
415 return out;
416 }
417
getPreferredRateNanos() const418 int64_t APerformanceHintManager::getPreferredRateNanos() const {
419 return mPreferredRateNanos;
420 }
421
getMaxGraphicsPipelineThreadsCount()422 int32_t APerformanceHintManager::getMaxGraphicsPipelineThreadsCount() {
423 if (!mMaxGraphicsPipelineThreadsCount.has_value()) {
424 int32_t threadsCount = -1;
425 ndk::ScopedAStatus ret = mHintManager->getMaxGraphicsPipelineThreadsCount(&threadsCount);
426 if (!ret.isOk()) {
427 ALOGE("%s: PerformanceHint cannot get max graphics pipeline threads count. %s",
428 __FUNCTION__, ret.getMessage());
429 return -1;
430 }
431 if (threadsCount <= 0) {
432 threadsCount = -1;
433 }
434 mMaxGraphicsPipelineThreadsCount.emplace(threadsCount);
435 }
436 return mMaxGraphicsPipelineThreadsCount.value();
437 }
438
getFMQWrapper()439 FMQWrapper& APerformanceHintManager::getFMQWrapper() {
440 return mFMQWrapper;
441 }
442
initJava(JNIEnv * _Nonnull env)443 void APerformanceHintManager::initJava(JNIEnv* _Nonnull env) {
444 if (mJavaInitialized) {
445 return;
446 }
447 jclass sessionClazz = FindClassOrDie(env, "android/os/PerformanceHintManager$Session");
448 mJavaSessionClazz = MakeGlobalRefOrDie(env, sessionClazz);
449 mJavaSessionNativePtr = GetFieldIDOrDie(env, mJavaSessionClazz, "mNativeSessionPtr", "J");
450 mJavaInitialized = true;
451 }
452
453 // ===================================== APerformanceHintSession implementation
454
455 constexpr int kNumEnums = enum_size<hal::SessionHint>();
APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,std::shared_ptr<IHintSession> session,int64_t preferredRateNanos,int64_t targetDurationNanos,bool isJava,std::optional<hal::SessionConfig> sessionConfig)456 APerformanceHintSession::APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
457 std::shared_ptr<IHintSession> session,
458 int64_t preferredRateNanos,
459 int64_t targetDurationNanos, bool isJava,
460 std::optional<hal::SessionConfig> sessionConfig)
461 : mHintManager(hintManager),
462 mHintSession(std::move(session)),
463 mPreferredRateNanos(preferredRateNanos),
464 mTargetDurationNanos(targetDurationNanos),
465 mFirstTargetMetTimestamp(0),
466 mLastTargetMetTimestamp(0),
467 mLastHintSentTimestamp(std::vector<int64_t>(kNumEnums, 0)),
468 mIsJava(isJava),
469 mSessionConfig(sessionConfig) {
470 if (sessionConfig->id > INT32_MAX) {
471 ALOGE("Session ID too large, must fit 32-bit integer");
472 }
473 int64_t traceId = sessionConfig.has_value() ? sessionConfig->id : ++sIDCounter;
474 mSessionName = android::base::StringPrintf("ADPF Session %" PRId64, traceId);
475 }
476
~APerformanceHintSession()477 APerformanceHintSession::~APerformanceHintSession() {
478 ndk::ScopedAStatus ret = mHintSession->close();
479 if (!ret.isOk()) {
480 ALOGE("%s: HintSession close failed: %s", __FUNCTION__, ret.getMessage());
481 }
482 }
483
updateTargetWorkDuration(int64_t targetDurationNanos)484 int APerformanceHintSession::updateTargetWorkDuration(int64_t targetDurationNanos) {
485 if (targetDurationNanos <= 0) {
486 ALOGE("%s: targetDurationNanos must be positive", __FUNCTION__);
487 return EINVAL;
488 }
489 std::scoped_lock lock(sHintMutex);
490 if (mTargetDurationNanos == targetDurationNanos) {
491 return 0;
492 }
493 if (!getFMQ().updateTargetWorkDuration(mSessionConfig, targetDurationNanos)) {
494 ndk::ScopedAStatus ret = mHintSession->updateTargetWorkDuration(targetDurationNanos);
495 if (!ret.isOk()) {
496 ALOGE("%s: HintSession updateTargetWorkDuration failed: %s", __FUNCTION__,
497 ret.getMessage());
498 return EPIPE;
499 }
500 }
501 mTargetDurationNanos = targetDurationNanos;
502 /**
503 * Most of the workload is target_duration dependent, so now clear the cached samples
504 * as they are most likely obsolete.
505 */
506 mActualWorkDurations.clear();
507 traceBatchSize(0);
508 traceTargetDuration(targetDurationNanos);
509 mFirstTargetMetTimestamp = 0;
510 mLastTargetMetTimestamp = 0;
511 return 0;
512 }
513
reportActualWorkDuration(int64_t actualDurationNanos)514 int APerformanceHintSession::reportActualWorkDuration(int64_t actualDurationNanos) {
515 hal::WorkDuration workDuration{.durationNanos = actualDurationNanos,
516 .workPeriodStartTimestampNanos = 0,
517 .cpuDurationNanos = actualDurationNanos,
518 .gpuDurationNanos = 0};
519
520 return reportActualWorkDurationInternal(static_cast<AWorkDuration*>(&workDuration));
521 }
522
isJava()523 bool APerformanceHintSession::isJava() {
524 return mIsJava;
525 }
526
sendHints(std::vector<hal::SessionHint> & hints,int64_t now,const char *)527 int APerformanceHintSession::sendHints(std::vector<hal::SessionHint>& hints, int64_t now,
528 const char*) {
529 std::scoped_lock lock(sHintMutex);
530 if (hints.empty()) {
531 return EINVAL;
532 }
533 for (auto&& hint : hints) {
534 if (static_cast<int32_t>(hint) < 0 || static_cast<int32_t>(hint) >= kNumEnums) {
535 ALOGE("%s: invalid session hint %d", __FUNCTION__, hint);
536 return EINVAL;
537 }
538 }
539
540 if (useNewLoadHintBehavior()) {
541 if (!APerformanceHintManager::getInstance()->canSendLoadHints(hints, now)) {
542 return EBUSY;
543 }
544 }
545 // keep old rate limiter behavior for legacy flag
546 else {
547 for (auto&& hint : hints) {
548 if (now < (mLastHintSentTimestamp[static_cast<int32_t>(hint)] + SEND_HINT_TIMEOUT)) {
549 return EBUSY;
550 }
551 }
552 }
553
554 if (!getFMQ().sendHints(mSessionConfig, hints, now)) {
555 for (auto&& hint : hints) {
556 ndk::ScopedAStatus ret = mHintSession->sendHint(static_cast<int32_t>(hint));
557
558 if (!ret.isOk()) {
559 ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.getMessage());
560 return EPIPE;
561 }
562 }
563 }
564
565 if (!useNewLoadHintBehavior()) {
566 for (auto&& hint : hints) {
567 mLastHintSentTimestamp[static_cast<int32_t>(hint)] = now;
568 }
569 }
570
571 if (ATrace_isEnabled()) {
572 ATRACE_INSTANT("Sending load hint");
573 }
574
575 return 0;
576 }
577
notifyWorkloadIncrease(bool cpu,bool gpu,const char * debugName)578 int APerformanceHintSession::notifyWorkloadIncrease(bool cpu, bool gpu, const char* debugName) {
579 std::vector<hal::SessionHint> hints(2);
580 hints.clear();
581 if (cpu) {
582 hints.push_back(hal::SessionHint::CPU_LOAD_UP);
583 }
584 if (gpu) {
585 hints.push_back(hal::SessionHint::GPU_LOAD_UP);
586 }
587 int64_t now = ::android::uptimeNanos();
588 return sendHints(hints, now, debugName);
589 }
590
notifyWorkloadReset(bool cpu,bool gpu,const char * debugName)591 int APerformanceHintSession::notifyWorkloadReset(bool cpu, bool gpu, const char* debugName) {
592 std::vector<hal::SessionHint> hints(2);
593 hints.clear();
594 if (cpu) {
595 hints.push_back(hal::SessionHint::CPU_LOAD_RESET);
596 }
597 if (gpu) {
598 hints.push_back(hal::SessionHint::GPU_LOAD_RESET);
599 }
600 int64_t now = ::android::uptimeNanos();
601 return sendHints(hints, now, debugName);
602 }
603
notifyWorkloadSpike(bool cpu,bool gpu,const char * debugName)604 int APerformanceHintSession::notifyWorkloadSpike(bool cpu, bool gpu, const char* debugName) {
605 std::vector<hal::SessionHint> hints(2);
606 hints.clear();
607 if (cpu) {
608 hints.push_back(hal::SessionHint::CPU_LOAD_SPIKE);
609 }
610 if (gpu) {
611 hints.push_back(hal::SessionHint::GPU_LOAD_SPIKE);
612 }
613 int64_t now = ::android::uptimeNanos();
614 return sendHints(hints, now, debugName);
615 }
616
setThreads(const int32_t * threadIds,size_t size)617 int APerformanceHintSession::setThreads(const int32_t* threadIds, size_t size) {
618 if (size == 0) {
619 ALOGE("%s: the list of thread ids must not be empty.", __FUNCTION__);
620 return EINVAL;
621 }
622 std::vector<int32_t> tids(threadIds, threadIds + size);
623 ndk::ScopedAStatus ret = mHintManager->setHintSessionThreads(mHintSession, tids);
624 if (!ret.isOk()) {
625 ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage());
626 if (ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT) {
627 return EINVAL;
628 } else if (ret.getExceptionCode() == EX_SECURITY) {
629 return EPERM;
630 }
631 return EPIPE;
632 }
633
634 std::scoped_lock lock(sHintMutex);
635 traceThreads(tids);
636
637 return 0;
638 }
639
getThreadIds(int32_t * const threadIds,size_t * size)640 int APerformanceHintSession::getThreadIds(int32_t* const threadIds, size_t* size) {
641 std::vector<int32_t> tids;
642 ndk::ScopedAStatus ret = mHintManager->getHintSessionThreadIds(mHintSession, &tids);
643 if (!ret.isOk()) {
644 ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage());
645 return EPIPE;
646 }
647
648 // When threadIds is nullptr, this is the first call to determine the size
649 // of the thread ids list.
650 if (threadIds == nullptr) {
651 *size = tids.size();
652 return 0;
653 }
654
655 // Second call to return the actual list of thread ids.
656 *size = tids.size();
657 for (size_t i = 0; i < *size; ++i) {
658 threadIds[i] = tids[i];
659 }
660 return 0;
661 }
662
setPreferPowerEfficiency(bool enabled)663 int APerformanceHintSession::setPreferPowerEfficiency(bool enabled) {
664 ndk::ScopedAStatus ret =
665 mHintSession->setMode(static_cast<int32_t>(hal::SessionMode::POWER_EFFICIENCY),
666 enabled);
667
668 if (!ret.isOk()) {
669 ALOGE("%s: HintSession setPreferPowerEfficiency failed: %s", __FUNCTION__,
670 ret.getMessage());
671 return EPIPE;
672 }
673 std::scoped_lock lock(sHintMutex);
674 tracePowerEfficient(enabled);
675 return OK;
676 }
677
reportActualWorkDuration(AWorkDuration * workDuration)678 int APerformanceHintSession::reportActualWorkDuration(AWorkDuration* workDuration) {
679 return reportActualWorkDurationInternal(workDuration);
680 }
681
reportActualWorkDurationInternal(AWorkDuration * workDuration)682 int APerformanceHintSession::reportActualWorkDurationInternal(AWorkDuration* workDuration) {
683 int64_t actualTotalDurationNanos = workDuration->durationNanos;
684 traceActualDuration(workDuration->durationNanos);
685 int64_t now = uptimeNanos();
686 workDuration->timeStampNanos = now;
687 std::scoped_lock lock(sHintMutex);
688 mActualWorkDurations.push_back(std::move(*workDuration));
689
690 if (actualTotalDurationNanos >= mTargetDurationNanos) {
691 // Reset timestamps if we are equal or over the target.
692 mFirstTargetMetTimestamp = 0;
693 } else {
694 // Set mFirstTargetMetTimestamp for first time meeting target.
695 if (!mFirstTargetMetTimestamp || !mLastTargetMetTimestamp ||
696 (now - mLastTargetMetTimestamp > 2 * mPreferredRateNanos)) {
697 mFirstTargetMetTimestamp = now;
698 }
699 /**
700 * Rate limit the change if the update is over mPreferredRateNanos since first
701 * meeting target and less than mPreferredRateNanos since last meeting target.
702 */
703 if (now - mFirstTargetMetTimestamp > mPreferredRateNanos &&
704 now - mLastTargetMetTimestamp <= mPreferredRateNanos) {
705 traceBatchSize(mActualWorkDurations.size());
706 return 0;
707 }
708 mLastTargetMetTimestamp = now;
709 }
710
711 if (!getFMQ().reportActualWorkDurations(mSessionConfig, mActualWorkDurations.data(),
712 mActualWorkDurations.size())) {
713 ndk::ScopedAStatus ret = mHintSession->reportActualWorkDuration2(mActualWorkDurations);
714 if (!ret.isOk()) {
715 ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__,
716 ret.getMessage());
717 mFirstTargetMetTimestamp = 0;
718 mLastTargetMetTimestamp = 0;
719 traceBatchSize(mActualWorkDurations.size());
720 return ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT ? EINVAL : EPIPE;
721 }
722 }
723
724 mActualWorkDurations.clear();
725 traceBatchSize(0);
726
727 return 0;
728 }
729
setNativeSurfaces(ANativeWindow ** windows,int numWindows,ASurfaceControl ** controls,int numSurfaceControls)730 status_t APerformanceHintSession::setNativeSurfaces(ANativeWindow** windows, int numWindows,
731 ASurfaceControl** controls,
732 int numSurfaceControls) {
733 if (!mSessionConfig.has_value()) {
734 return ENOTSUP;
735 }
736
737 std::vector<sp<IBinder>> layerHandles;
738 APerformanceHintManager::layersFromNativeSurfaces<sp<IBinder>>(windows, numWindows, controls,
739 numSurfaceControls,
740 layerHandles);
741
742 std::vector<ndk::SpAIBinder> ndkLayerHandles;
743 for (auto&& handle : layerHandles) {
744 ndkLayerHandles.emplace_back(ndk::SpAIBinder(AIBinder_fromPlatformBinder(handle)));
745 }
746
747 mHintSession->associateToLayers(ndkLayerHandles);
748 return 0;
749 }
750
751 template <class T>
layersFromNativeSurfaces(ANativeWindow ** windows,int numWindows,ASurfaceControl ** controls,int numSurfaceControls,std::vector<T> & out)752 void APerformanceHintManager::layersFromNativeSurfaces(ANativeWindow** windows, int numWindows,
753 ASurfaceControl** controls,
754 int numSurfaceControls,
755 std::vector<T>& out) {
756 std::scoped_lock lock(sHintMutex);
757 if (windows != nullptr) {
758 std::vector<ANativeWindow*> windowVec(windows, windows + numWindows);
759 for (auto&& window : windowVec) {
760 Surface* surface = static_cast<Surface*>(window);
761 if (Surface::isValid(surface)) {
762 const sp<IBinder>& handle = surface->getSurfaceControlHandle();
763 if (handle != nullptr) {
764 out.push_back(handle);
765 }
766 }
767 }
768 }
769
770 if (controls != nullptr) {
771 std::vector<ASurfaceControl*> controlVec(controls, controls + numSurfaceControls);
772 for (auto&& aSurfaceControl : controlVec) {
773 SurfaceControl* control = reinterpret_cast<SurfaceControl*>(aSurfaceControl);
774 if (control->isValid()) {
775 out.push_back(control->getHandle());
776 }
777 }
778 }
779 }
780
781 // ===================================== FMQ wrapper implementation
782
isActive()783 bool FMQWrapper::isActive() {
784 std::scoped_lock lock{sHintMutex};
785 return isActiveLocked();
786 }
787
isActiveLocked()788 bool FMQWrapper::isActiveLocked() {
789 return mQueue != nullptr;
790 }
791
setUnsupported()792 void FMQWrapper::setUnsupported() {
793 mHalSupported = false;
794 }
795
isSupported()796 bool FMQWrapper::isSupported() {
797 if (!mHalSupported) {
798 return false;
799 }
800 // Used for testing
801 if (gForceFMQEnabled.has_value()) {
802 return *gForceFMQEnabled;
803 }
804 return android::os::adpf_use_fmq_channel_fixed();
805 }
806
startChannel(IHintManager * manager)807 bool FMQWrapper::startChannel(IHintManager* manager) {
808 if (isSupported() && !isActive() && manager->isRemote()) {
809 mChannelCreationFinished = std::async(std::launch::async, [&, this, manager]() {
810 std::optional<hal::ChannelConfig> config;
811 auto ret = manager->getSessionChannel(mToken, &config);
812 if (ret.isOk() && config.has_value()) {
813 std::scoped_lock lock{sHintMutex};
814 mQueue = std::make_shared<HalMessageQueue>(config->channelDescriptor, true);
815 if (config->eventFlagDescriptor.has_value()) {
816 mFlagQueue = std::make_shared<HalFlagQueue>(*config->eventFlagDescriptor, true);
817 android::hardware::EventFlag::createEventFlag(mFlagQueue->getEventFlagWord(),
818 &mEventFlag);
819 mWriteMask = config->writeFlagBitmask;
820 }
821 updatePersistentTransaction();
822 } else if (ret.isOk() && !config.has_value()) {
823 ALOGV("FMQ channel enabled but unsupported.");
824 setUnsupported();
825 } else {
826 ALOGE("%s: FMQ channel initialization failed: %s", __FUNCTION__, ret.getMessage());
827 }
828 return true;
829 });
830 }
831 return isActive();
832 }
833
stopChannel(IHintManager * manager)834 void FMQWrapper::stopChannel(IHintManager* manager) {
835 {
836 std::scoped_lock lock{sHintMutex};
837 if (!isActiveLocked()) {
838 return;
839 }
840 mFlagQueue = nullptr;
841 mQueue = nullptr;
842 }
843 manager->closeSessionChannel();
844 }
845
846 template <HalChannelMessageContents::Tag T, class C>
writeBuffer(C * message,hal::SessionConfig & config,size_t count,int64_t now)847 void FMQWrapper::writeBuffer(C* message, hal::SessionConfig& config, size_t count, int64_t now) {
848 for (size_t i = 0; i < count; ++i) {
849 new (mFmqTransaction.getSlot(i)) hal::ChannelMessage{
850 .sessionID = static_cast<int32_t>(config.id),
851 .timeStampNanos = now,
852 .data = HalChannelMessageContents::make<T, C>(std::move(*(message + i))),
853 };
854 }
855 }
856
857 template <>
writeBuffer(hal::WorkDuration * messages,hal::SessionConfig & config,size_t count,int64_t now)858 void FMQWrapper::writeBuffer<HalChannelMessageContents::workDuration>(hal::WorkDuration* messages,
859 hal::SessionConfig& config,
860 size_t count, int64_t now) {
861 for (size_t i = 0; i < count; ++i) {
862 hal::WorkDuration& message = messages[i];
863 new (mFmqTransaction.getSlot(i)) hal::ChannelMessage{
864 .sessionID = static_cast<int32_t>(config.id),
865 .timeStampNanos = (i == count - 1) ? now : message.timeStampNanos,
866 .data = HalChannelMessageContents::make<HalChannelMessageContents::workDuration,
867 hal::WorkDurationFixedV1>({
868 .durationNanos = message.cpuDurationNanos,
869 .workPeriodStartTimestampNanos = message.workPeriodStartTimestampNanos,
870 .cpuDurationNanos = message.cpuDurationNanos,
871 .gpuDurationNanos = message.gpuDurationNanos,
872 }),
873 };
874 }
875 }
876
877 template <HalChannelMessageContents::Tag T, bool urgent, class C>
sendMessages(std::optional<hal::SessionConfig> & config,C * message,size_t count,int64_t now)878 bool FMQWrapper::sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count,
879 int64_t now) {
880 if (!isActiveLocked() || !config.has_value() || mCorrupted) {
881 return false;
882 }
883 // If we didn't reserve enough space, try re-creating the transaction
884 if (count > mAvailableSlots) {
885 if (!updatePersistentTransaction()) {
886 return false;
887 }
888 // If we actually don't have enough space, give up
889 if (count > mAvailableSlots) {
890 return false;
891 }
892 }
893 writeBuffer<T, C>(message, *config, count, now);
894 mQueue->commitWrite(count);
895 mEventFlag->wake(mWriteMask);
896 // Re-create the persistent transaction after writing
897 updatePersistentTransaction();
898 return true;
899 }
900
setToken(ndk::SpAIBinder & token)901 void FMQWrapper::setToken(ndk::SpAIBinder& token) {
902 mToken = token;
903 }
904
updatePersistentTransaction()905 bool FMQWrapper::updatePersistentTransaction() {
906 mAvailableSlots = mQueue->availableToWrite();
907 if (mAvailableSlots > 0 && !mQueue->beginWrite(mAvailableSlots, &mFmqTransaction)) {
908 ALOGE("ADPF FMQ became corrupted, falling back to binder calls!");
909 mCorrupted = true;
910 return false;
911 }
912 return true;
913 }
914
reportActualWorkDurations(std::optional<hal::SessionConfig> & config,hal::WorkDuration * durations,size_t count)915 bool FMQWrapper::reportActualWorkDurations(std::optional<hal::SessionConfig>& config,
916 hal::WorkDuration* durations, size_t count) {
917 return sendMessages<HalChannelMessageContents::workDuration>(config, durations, count);
918 }
919
updateTargetWorkDuration(std::optional<hal::SessionConfig> & config,int64_t targetDurationNanos)920 bool FMQWrapper::updateTargetWorkDuration(std::optional<hal::SessionConfig>& config,
921 int64_t targetDurationNanos) {
922 return sendMessages<HalChannelMessageContents::targetDuration>(config, &targetDurationNanos);
923 }
924
sendHints(std::optional<hal::SessionConfig> & config,std::vector<hal::SessionHint> & hints,int64_t now)925 bool FMQWrapper::sendHints(std::optional<hal::SessionConfig>& config,
926 std::vector<hal::SessionHint>& hints, int64_t now) {
927 return sendMessages<HalChannelMessageContents::hint>(config, hints.data(), hints.size(), now);
928 }
929
setMode(std::optional<hal::SessionConfig> & config,hal::SessionMode mode,bool enabled)930 bool FMQWrapper::setMode(std::optional<hal::SessionConfig>& config, hal::SessionMode mode,
931 bool enabled) {
932 hal::ChannelMessage::ChannelMessageContents::SessionModeSetter modeObj{.modeInt = mode,
933 .enabled = enabled};
934 return sendMessages<HalChannelMessageContents::mode, true>(config, &modeObj);
935 }
936
937 // ===================================== Tracing helpers
938
traceThreads(const std::vector<int32_t> & tids)939 void APerformanceHintSession::traceThreads(const std::vector<int32_t>& tids) {
940 std::set<int32_t> tidSet{tids.begin(), tids.end()};
941
942 // Disable old TID tracing
943 for (int32_t tid : mLastThreadIDs) {
944 if (!tidSet.count(tid)) {
945 std::string traceName =
946 android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
947 ATrace_setCounter(traceName.c_str(), 0);
948 }
949 }
950
951 // Add new TID tracing
952 for (int32_t tid : tids) {
953 std::string traceName =
954 android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
955 ATrace_setCounter(traceName.c_str(), 1);
956 }
957
958 mLastThreadIDs = std::move(tids);
959 }
960
tracePowerEfficient(bool powerEfficient)961 void APerformanceHintSession::tracePowerEfficient(bool powerEfficient) {
962 ATrace_setCounter((mSessionName + " power efficiency mode").c_str(), powerEfficient);
963 }
964
traceGraphicsPipeline(bool graphicsPipeline)965 void APerformanceHintSession::traceGraphicsPipeline(bool graphicsPipeline) {
966 ATrace_setCounter((mSessionName + " graphics pipeline mode").c_str(), graphicsPipeline);
967 }
968
traceModes(const std::vector<hal::SessionMode> & modesToEnable)969 void APerformanceHintSession::traceModes(const std::vector<hal::SessionMode>& modesToEnable) {
970 // Iterate through all modes to trace, set to enable for all modes in modesToEnable,
971 // and set to disable for those are not.
972 for (hal::SessionMode mode :
973 {hal::SessionMode::POWER_EFFICIENCY, hal::SessionMode::GRAPHICS_PIPELINE}) {
974 bool isEnabled =
975 find(modesToEnable.begin(), modesToEnable.end(), mode) != modesToEnable.end();
976 switch (mode) {
977 case hal::SessionMode::POWER_EFFICIENCY:
978 tracePowerEfficient(isEnabled);
979 break;
980 case hal::SessionMode::GRAPHICS_PIPELINE:
981 traceGraphicsPipeline(isEnabled);
982 break;
983 default:
984 break;
985 }
986 }
987 }
988
traceActualDuration(int64_t actualDuration)989 void APerformanceHintSession::traceActualDuration(int64_t actualDuration) {
990 ATrace_setCounter((mSessionName + " actual duration").c_str(), actualDuration);
991 }
992
traceBatchSize(size_t batchSize)993 void APerformanceHintSession::traceBatchSize(size_t batchSize) {
994 std::string traceName = StringPrintf("%s batch size", mSessionName.c_str());
995 ATrace_setCounter((mSessionName + " batch size").c_str(), batchSize);
996 }
997
traceTargetDuration(int64_t targetDuration)998 void APerformanceHintSession::traceTargetDuration(int64_t targetDuration) {
999 ATrace_setCounter((mSessionName + " target duration").c_str(), targetDuration);
1000 }
1001
1002 // ===================================== C API
APerformanceHint_getManager()1003 APerformanceHintManager* APerformanceHint_getManager() {
1004 return APerformanceHintManager::getInstance();
1005 }
1006
1007 #define VALIDATE_PTR(ptr) \
1008 LOG_ALWAYS_FATAL_IF(ptr == nullptr, "%s: " #ptr " is nullptr", __FUNCTION__);
1009
1010 #define VALIDATE_INT(value, cmp) \
1011 if (!(value cmp)) { \
1012 ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
1013 __FUNCTION__, value); \
1014 return EINVAL; \
1015 }
1016
1017 #define WARN_INT(value, cmp) \
1018 if (!(value cmp)) { \
1019 ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
1020 __FUNCTION__, value); \
1021 }
1022
APerformanceHint_createSession(APerformanceHintManager * manager,const int32_t * threadIds,size_t size,int64_t initialTargetWorkDurationNanos)1023 APerformanceHintSession* APerformanceHint_createSession(APerformanceHintManager* manager,
1024 const int32_t* threadIds, size_t size,
1025 int64_t initialTargetWorkDurationNanos) {
1026 VALIDATE_PTR(manager)
1027 VALIDATE_PTR(threadIds)
1028 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos);
1029 }
1030
APerformanceHint_createSessionUsingConfig(APerformanceHintManager * manager,ASessionCreationConfig * sessionCreationConfig)1031 APerformanceHintSession* APerformanceHint_createSessionUsingConfig(
1032 APerformanceHintManager* manager, ASessionCreationConfig* sessionCreationConfig) {
1033 VALIDATE_PTR(manager);
1034 VALIDATE_PTR(sessionCreationConfig);
1035 return manager->createSessionUsingConfig(sessionCreationConfig);
1036 }
1037
APerformanceHint_createSessionUsingConfigInternal(APerformanceHintManager * manager,ASessionCreationConfig * sessionCreationConfig,SessionTag tag)1038 APerformanceHintSession* APerformanceHint_createSessionUsingConfigInternal(
1039 APerformanceHintManager* manager, ASessionCreationConfig* sessionCreationConfig,
1040 SessionTag tag) {
1041 VALIDATE_PTR(manager);
1042 VALIDATE_PTR(sessionCreationConfig);
1043 return manager->createSessionUsingConfig(sessionCreationConfig,
1044 static_cast<hal::SessionTag>(tag));
1045 }
1046
APerformanceHint_createSessionInternal(APerformanceHintManager * manager,const int32_t * threadIds,size_t size,int64_t initialTargetWorkDurationNanos,SessionTag tag)1047 APerformanceHintSession* APerformanceHint_createSessionInternal(
1048 APerformanceHintManager* manager, const int32_t* threadIds, size_t size,
1049 int64_t initialTargetWorkDurationNanos, SessionTag tag) {
1050 VALIDATE_PTR(manager)
1051 VALIDATE_PTR(threadIds)
1052 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos,
1053 static_cast<hal::SessionTag>(tag));
1054 }
1055
APerformanceHint_createSessionFromJava(APerformanceHintManager * manager,const int32_t * threadIds,size_t size,int64_t initialTargetWorkDurationNanos)1056 APerformanceHintSession* APerformanceHint_createSessionFromJava(
1057 APerformanceHintManager* manager, const int32_t* threadIds, size_t size,
1058 int64_t initialTargetWorkDurationNanos) {
1059 VALIDATE_PTR(manager)
1060 VALIDATE_PTR(threadIds)
1061 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos,
1062 hal::SessionTag::APP, true);
1063 }
1064
APerformanceHint_borrowSessionFromJava(JNIEnv * env,jobject sessionObj)1065 APerformanceHintSession* APerformanceHint_borrowSessionFromJava(JNIEnv* env, jobject sessionObj) {
1066 VALIDATE_PTR(env)
1067 VALIDATE_PTR(sessionObj)
1068 return APerformanceHintManager::getInstance()->getSessionFromJava(env, sessionObj);
1069 }
1070
APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager * manager)1071 int64_t APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager* manager) {
1072 VALIDATE_PTR(manager)
1073 return manager->getPreferredRateNanos();
1074 }
1075
APerformanceHint_getMaxGraphicsPipelineThreadsCount(APerformanceHintManager * manager)1076 int APerformanceHint_getMaxGraphicsPipelineThreadsCount(APerformanceHintManager* manager) {
1077 VALIDATE_PTR(manager);
1078 return manager->getMaxGraphicsPipelineThreadsCount();
1079 }
1080
APerformanceHint_updateTargetWorkDuration(APerformanceHintSession * session,int64_t targetDurationNanos)1081 int APerformanceHint_updateTargetWorkDuration(APerformanceHintSession* session,
1082 int64_t targetDurationNanos) {
1083 VALIDATE_PTR(session)
1084 return session->updateTargetWorkDuration(targetDurationNanos);
1085 }
1086
APerformanceHint_reportActualWorkDuration(APerformanceHintSession * session,int64_t actualDurationNanos)1087 int APerformanceHint_reportActualWorkDuration(APerformanceHintSession* session,
1088 int64_t actualDurationNanos) {
1089 VALIDATE_PTR(session)
1090 VALIDATE_INT(actualDurationNanos, > 0)
1091 return session->reportActualWorkDuration(actualDurationNanos);
1092 }
1093
APerformanceHint_closeSession(APerformanceHintSession * session)1094 void APerformanceHint_closeSession(APerformanceHintSession* session) {
1095 VALIDATE_PTR(session)
1096 if (session->isJava()) {
1097 LOG_ALWAYS_FATAL("%s: Java-owned PerformanceHintSession cannot be closed in native",
1098 __FUNCTION__);
1099 return;
1100 }
1101 delete session;
1102 }
1103
APerformanceHint_closeSessionFromJava(APerformanceHintSession * session)1104 void APerformanceHint_closeSessionFromJava(APerformanceHintSession* session) {
1105 VALIDATE_PTR(session)
1106 delete session;
1107 }
1108
APerformanceHint_sendHint(APerformanceHintSession * session,SessionHint hint)1109 int APerformanceHint_sendHint(APerformanceHintSession* session, SessionHint hint) {
1110 VALIDATE_PTR(session)
1111 std::vector<hal::SessionHint> hints{static_cast<hal::SessionHint>(hint)};
1112 int64_t now = ::android::uptimeNanos();
1113 return session->sendHints(hints, now, "HWUI hint");
1114 }
1115
APerformanceHint_setThreads(APerformanceHintSession * session,const pid_t * threadIds,size_t size)1116 int APerformanceHint_setThreads(APerformanceHintSession* session, const pid_t* threadIds,
1117 size_t size) {
1118 VALIDATE_PTR(session)
1119 VALIDATE_PTR(threadIds)
1120 return session->setThreads(threadIds, size);
1121 }
1122
APerformanceHint_getThreadIds(APerformanceHintSession * session,int32_t * const threadIds,size_t * const size)1123 int APerformanceHint_getThreadIds(APerformanceHintSession* session, int32_t* const threadIds,
1124 size_t* const size) {
1125 VALIDATE_PTR(session)
1126 return session->getThreadIds(threadIds, size);
1127 }
1128
APerformanceHint_setPreferPowerEfficiency(APerformanceHintSession * session,bool enabled)1129 int APerformanceHint_setPreferPowerEfficiency(APerformanceHintSession* session, bool enabled) {
1130 VALIDATE_PTR(session)
1131 return session->setPreferPowerEfficiency(enabled);
1132 }
1133
APerformanceHint_reportActualWorkDuration2(APerformanceHintSession * session,AWorkDuration * workDurationPtr)1134 int APerformanceHint_reportActualWorkDuration2(APerformanceHintSession* session,
1135 AWorkDuration* workDurationPtr) {
1136 VALIDATE_PTR(session)
1137 VALIDATE_PTR(workDurationPtr)
1138 VALIDATE_INT(workDurationPtr->durationNanos, > 0)
1139 VALIDATE_INT(workDurationPtr->workPeriodStartTimestampNanos, > 0)
1140 VALIDATE_INT(workDurationPtr->cpuDurationNanos, >= 0)
1141 VALIDATE_INT(workDurationPtr->gpuDurationNanos, >= 0)
1142 VALIDATE_INT(workDurationPtr->gpuDurationNanos + workDurationPtr->cpuDurationNanos, > 0)
1143 return session->reportActualWorkDuration(workDurationPtr);
1144 }
1145
APerformanceHint_notifyWorkloadIncrease(APerformanceHintSession * session,bool cpu,bool gpu,const char * debugName)1146 int APerformanceHint_notifyWorkloadIncrease(APerformanceHintSession* session, bool cpu, bool gpu,
1147 const char* debugName) {
1148 VALIDATE_PTR(session)
1149 VALIDATE_PTR(debugName)
1150 if (!useNewLoadHintBehavior()) {
1151 return ENOTSUP;
1152 }
1153 return session->notifyWorkloadIncrease(cpu, gpu, debugName);
1154 }
1155
APerformanceHint_notifyWorkloadReset(APerformanceHintSession * session,bool cpu,bool gpu,const char * debugName)1156 int APerformanceHint_notifyWorkloadReset(APerformanceHintSession* session, bool cpu, bool gpu,
1157 const char* debugName) {
1158 VALIDATE_PTR(session)
1159 VALIDATE_PTR(debugName)
1160 if (!useNewLoadHintBehavior()) {
1161 return ENOTSUP;
1162 }
1163 return session->notifyWorkloadReset(cpu, gpu, debugName);
1164 }
1165
APerformanceHint_notifyWorkloadSpike(APerformanceHintSession * session,bool cpu,bool gpu,const char * debugName)1166 int APerformanceHint_notifyWorkloadSpike(APerformanceHintSession* session, bool cpu, bool gpu,
1167 const char* debugName) {
1168 VALIDATE_PTR(session)
1169 VALIDATE_PTR(debugName)
1170 if (!useNewLoadHintBehavior()) {
1171 return ENOTSUP;
1172 }
1173 return session->notifyWorkloadSpike(cpu, gpu, debugName);
1174 }
1175
APerformanceHint_setNativeSurfaces(APerformanceHintSession * session,ANativeWindow ** nativeWindows,int nativeWindowsSize,ASurfaceControl ** surfaceControls,int surfaceControlsSize)1176 int APerformanceHint_setNativeSurfaces(APerformanceHintSession* session,
1177 ANativeWindow** nativeWindows, int nativeWindowsSize,
1178 ASurfaceControl** surfaceControls, int surfaceControlsSize) {
1179 VALIDATE_PTR(session)
1180 return session->setNativeSurfaces(nativeWindows, nativeWindowsSize, surfaceControls,
1181 surfaceControlsSize);
1182 }
1183
AWorkDuration_create()1184 AWorkDuration* AWorkDuration_create() {
1185 return new AWorkDuration();
1186 }
1187
AWorkDuration_release(AWorkDuration * aWorkDuration)1188 void AWorkDuration_release(AWorkDuration* aWorkDuration) {
1189 VALIDATE_PTR(aWorkDuration)
1190 delete aWorkDuration;
1191 }
1192
AWorkDuration_setActualTotalDurationNanos(AWorkDuration * aWorkDuration,int64_t actualTotalDurationNanos)1193 void AWorkDuration_setActualTotalDurationNanos(AWorkDuration* aWorkDuration,
1194 int64_t actualTotalDurationNanos) {
1195 VALIDATE_PTR(aWorkDuration)
1196 WARN_INT(actualTotalDurationNanos, > 0)
1197 aWorkDuration->durationNanos = actualTotalDurationNanos;
1198 }
1199
AWorkDuration_setWorkPeriodStartTimestampNanos(AWorkDuration * aWorkDuration,int64_t workPeriodStartTimestampNanos)1200 void AWorkDuration_setWorkPeriodStartTimestampNanos(AWorkDuration* aWorkDuration,
1201 int64_t workPeriodStartTimestampNanos) {
1202 VALIDATE_PTR(aWorkDuration)
1203 WARN_INT(workPeriodStartTimestampNanos, > 0)
1204 aWorkDuration->workPeriodStartTimestampNanos = workPeriodStartTimestampNanos;
1205 }
1206
AWorkDuration_setActualCpuDurationNanos(AWorkDuration * aWorkDuration,int64_t actualCpuDurationNanos)1207 void AWorkDuration_setActualCpuDurationNanos(AWorkDuration* aWorkDuration,
1208 int64_t actualCpuDurationNanos) {
1209 VALIDATE_PTR(aWorkDuration)
1210 WARN_INT(actualCpuDurationNanos, >= 0)
1211 aWorkDuration->cpuDurationNanos = actualCpuDurationNanos;
1212 }
1213
AWorkDuration_setActualGpuDurationNanos(AWorkDuration * aWorkDuration,int64_t actualGpuDurationNanos)1214 void AWorkDuration_setActualGpuDurationNanos(AWorkDuration* aWorkDuration,
1215 int64_t actualGpuDurationNanos) {
1216 VALIDATE_PTR(aWorkDuration)
1217 WARN_INT(actualGpuDurationNanos, >= 0)
1218 aWorkDuration->gpuDurationNanos = actualGpuDurationNanos;
1219 }
1220
APerformanceHint_setIHintManagerForTesting(void * iManager)1221 void APerformanceHint_setIHintManagerForTesting(void* iManager) {
1222 if (iManager == nullptr) {
1223 gHintManagerForTesting = nullptr;
1224 }
1225 gIHintManagerForTesting = static_cast<std::shared_ptr<IHintManager>*>(iManager);
1226 }
1227
APerformanceHint_setUseFMQForTesting(bool enabled)1228 void APerformanceHint_setUseFMQForTesting(bool enabled) {
1229 gForceFMQEnabled = enabled;
1230 }
1231
ASessionCreationConfig_create()1232 ASessionCreationConfig* ASessionCreationConfig_create() {
1233 return new ASessionCreationConfig();
1234 }
1235
ASessionCreationConfig_release(ASessionCreationConfig * config)1236 void ASessionCreationConfig_release(ASessionCreationConfig* config) {
1237 VALIDATE_PTR(config)
1238
1239 delete config;
1240 }
1241
ASessionCreationConfig_setTids(ASessionCreationConfig * config,const pid_t * tids,size_t size)1242 int ASessionCreationConfig_setTids(ASessionCreationConfig* config, const pid_t* tids, size_t size) {
1243 VALIDATE_PTR(config)
1244 VALIDATE_PTR(tids)
1245
1246 if (!useGraphicsPipeline()) {
1247 return ENOTSUP;
1248 }
1249
1250 if (size <= 0) {
1251 LOG_ALWAYS_FATAL_IF(size <= 0,
1252 "%s: Invalid value. Thread id list size should be greater than zero.",
1253 __FUNCTION__);
1254 return EINVAL;
1255 }
1256 config->tids = std::vector<int32_t>(tids, tids + size);
1257 return 0;
1258 }
1259
ASessionCreationConfig_setTargetWorkDurationNanos(ASessionCreationConfig * config,int64_t targetWorkDurationNanos)1260 int ASessionCreationConfig_setTargetWorkDurationNanos(ASessionCreationConfig* config,
1261 int64_t targetWorkDurationNanos) {
1262 VALIDATE_PTR(config)
1263 VALIDATE_INT(targetWorkDurationNanos, >= 0)
1264
1265 if (!useGraphicsPipeline()) {
1266 return ENOTSUP;
1267 }
1268
1269 config->targetWorkDurationNanos = targetWorkDurationNanos;
1270 return 0;
1271 }
1272
ASessionCreationConfig_setPreferPowerEfficiency(ASessionCreationConfig * config,bool enabled)1273 int ASessionCreationConfig_setPreferPowerEfficiency(ASessionCreationConfig* config, bool enabled) {
1274 VALIDATE_PTR(config)
1275
1276 if (!useGraphicsPipeline()) {
1277 return ENOTSUP;
1278 }
1279
1280 if (enabled) {
1281 config->modesToEnable.push_back(hal::SessionMode::POWER_EFFICIENCY);
1282 } else {
1283 std::erase(config->modesToEnable, hal::SessionMode::POWER_EFFICIENCY);
1284 }
1285 return 0;
1286 }
1287
ASessionCreationConfig_setGraphicsPipeline(ASessionCreationConfig * config,bool enabled)1288 int ASessionCreationConfig_setGraphicsPipeline(ASessionCreationConfig* config, bool enabled) {
1289 VALIDATE_PTR(config)
1290
1291 if (!useGraphicsPipeline()) {
1292 return ENOTSUP;
1293 }
1294
1295 if (enabled) {
1296 config->modesToEnable.push_back(hal::SessionMode::GRAPHICS_PIPELINE);
1297 } else {
1298 std::erase(config->modesToEnable, hal::SessionMode::GRAPHICS_PIPELINE);
1299
1300 // Remove automatic timing modes if we turn off GRAPHICS_PIPELINE,
1301 // as it is a strict pre-requisite for these to run
1302 std::erase(config->modesToEnable, hal::SessionMode::AUTO_CPU);
1303 std::erase(config->modesToEnable, hal::SessionMode::AUTO_GPU);
1304 }
1305 return 0;
1306 }
1307
APerformanceHint_setUseGraphicsPipelineForTesting(bool enabled)1308 void APerformanceHint_setUseGraphicsPipelineForTesting(bool enabled) {
1309 kForceGraphicsPipeline = enabled;
1310 }
1311
APerformanceHint_getRateLimiterPropertiesForTesting(int32_t * maxLoadHintsPerInterval,int64_t * loadHintInterval)1312 void APerformanceHint_getRateLimiterPropertiesForTesting(int32_t* maxLoadHintsPerInterval,
1313 int64_t* loadHintInterval) {
1314 *maxLoadHintsPerInterval = kMaxLoadHintsPerInterval;
1315 *loadHintInterval = kLoadHintInterval;
1316 }
1317
APerformanceHint_setUseNewLoadHintBehaviorForTesting(bool newBehavior)1318 void APerformanceHint_setUseNewLoadHintBehaviorForTesting(bool newBehavior) {
1319 kForceNewHintBehavior = newBehavior;
1320 }
1321
ASessionCreationConfig_setNativeSurfaces(ASessionCreationConfig * config,ANativeWindow ** nativeWindows,int nativeWindowsSize,ASurfaceControl ** surfaceControls,int surfaceControlsSize)1322 int ASessionCreationConfig_setNativeSurfaces(ASessionCreationConfig* config,
1323 ANativeWindow** nativeWindows, int nativeWindowsSize,
1324 ASurfaceControl** surfaceControls,
1325 int surfaceControlsSize) {
1326 VALIDATE_PTR(config)
1327
1328 APerformanceHintManager::layersFromNativeSurfaces<wp<IBinder>>(nativeWindows, nativeWindowsSize,
1329 surfaceControls,
1330 surfaceControlsSize,
1331 config->layers);
1332
1333 if (config->layers.empty()) {
1334 return EINVAL;
1335 }
1336
1337 return 0;
1338 }
1339
ASessionCreationConfig_setUseAutoTiming(ASessionCreationConfig * _Nonnull config,bool cpu,bool gpu)1340 int ASessionCreationConfig_setUseAutoTiming(ASessionCreationConfig* _Nonnull config, bool cpu,
1341 bool gpu) {
1342 VALIDATE_PTR(config)
1343 if ((cpu || gpu) && !config->hasMode(hal::SessionMode::GRAPHICS_PIPELINE)) {
1344 ALOGE("Automatic timing is not supported unless graphics pipeline mode is enabled first");
1345 return ENOTSUP;
1346 }
1347
1348 if (config->hasMode(hal::SessionMode::AUTO_CPU)) {
1349 if (!cpu) {
1350 std::erase(config->modesToEnable, hal::SessionMode::AUTO_CPU);
1351 }
1352 } else if (cpu) {
1353 config->modesToEnable.push_back(static_cast<hal::SessionMode>(hal::SessionMode::AUTO_CPU));
1354 }
1355
1356 if (config->hasMode(hal::SessionMode::AUTO_GPU)) {
1357 if (!gpu) {
1358 std::erase(config->modesToEnable, hal::SessionMode::AUTO_GPU);
1359 }
1360 } else if (gpu) {
1361 config->modesToEnable.push_back(static_cast<hal::SessionMode>(hal::SessionMode::AUTO_GPU));
1362 }
1363
1364 return 0;
1365 }
1366