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