xref: /aosp_15_r20/frameworks/base/native/android/performance_hint.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
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