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/SessionHint.h>
20 #include <aidl/android/hardware/power/SessionMode.h>
21 #include <aidl/android/hardware/power/SessionTag.h>
22 #include <aidl/android/hardware/power/WorkDuration.h>
23 #include <aidl/android/os/IHintManager.h>
24 #include <aidl/android/os/IHintSession.h>
25 #include <android-base/stringprintf.h>
26 #include <android/binder_manager.h>
27 #include <android/binder_status.h>
28 #include <android/performance_hint.h>
29 #include <android/trace.h>
30 #include <inttypes.h>
31 #include <performance_hint_private.h>
32 #include <utils/SystemClock.h>
33
34 #include <chrono>
35 #include <set>
36 #include <utility>
37 #include <vector>
38
39 using namespace android;
40 using namespace aidl::android::os;
41
42 using namespace std::chrono_literals;
43
44 // Namespace for AIDL types coming from the PowerHAL
45 namespace hal = aidl::android::hardware::power;
46
47 using android::base::StringPrintf;
48
49 struct APerformanceHintSession;
50
51 constexpr int64_t SEND_HINT_TIMEOUT = std::chrono::nanoseconds(100ms).count();
52 struct AWorkDuration : public hal::WorkDuration {};
53
54 // Shared lock for the whole PerformanceHintManager and sessions
55 static std::mutex sHintMutex = std::mutex{};
56
57 struct APerformanceHintManager {
58 public:
59 static APerformanceHintManager* getInstance();
60 APerformanceHintManager(std::shared_ptr<IHintManager> service, int64_t preferredRateNanos);
61 APerformanceHintManager() = delete;
62 ~APerformanceHintManager() = default;
63
64 APerformanceHintSession* createSession(const int32_t* threadIds, size_t size,
65 int64_t initialTargetWorkDurationNanos,
66 hal::SessionTag tag = hal::SessionTag::APP);
67 int64_t getPreferredRateNanos() const;
68
69 private:
70 // Necessary to create an empty binder object
tokenStubOnCreateAPerformanceHintManager71 static void* tokenStubOnCreate(void*) {
72 return nullptr;
73 }
tokenStubOnDestroyAPerformanceHintManager74 static void tokenStubOnDestroy(void*) {}
tokenStubOnTransactAPerformanceHintManager75 static binder_status_t tokenStubOnTransact(AIBinder*, transaction_code_t, const AParcel*,
76 AParcel*) {
77 return STATUS_OK;
78 }
79
80 static APerformanceHintManager* create(std::shared_ptr<IHintManager> iHintManager);
81
82 std::shared_ptr<IHintManager> mHintManager;
83 ndk::SpAIBinder mToken;
84 const int64_t mPreferredRateNanos;
85 };
86
87 struct APerformanceHintSession {
88 public:
89 APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
90 std::shared_ptr<IHintSession> session, int64_t preferredRateNanos,
91 int64_t targetDurationNanos,
92 std::optional<hal::SessionConfig> sessionConfig);
93 APerformanceHintSession() = delete;
94 ~APerformanceHintSession();
95
96 int updateTargetWorkDuration(int64_t targetDurationNanos);
97 int reportActualWorkDuration(int64_t actualDurationNanos);
98 int sendHint(SessionHint hint);
99 int setThreads(const int32_t* threadIds, size_t size);
100 int getThreadIds(int32_t* const threadIds, size_t* size);
101 int setPreferPowerEfficiency(bool enabled);
102 int reportActualWorkDuration(AWorkDuration* workDuration);
103
104 private:
105 friend struct APerformanceHintManager;
106
107 int reportActualWorkDurationInternal(AWorkDuration* workDuration);
108
109 std::shared_ptr<IHintManager> mHintManager;
110 std::shared_ptr<IHintSession> mHintSession;
111 // HAL preferred update rate
112 const int64_t mPreferredRateNanos;
113 // Target duration for choosing update rate
114 int64_t mTargetDurationNanos;
115 // First target hit timestamp
116 int64_t mFirstTargetMetTimestamp;
117 // Last target hit timestamp
118 int64_t mLastTargetMetTimestamp;
119 // Last hint reported from sendHint indexed by hint value
120 std::vector<int64_t> mLastHintSentTimestamp;
121 // Cached samples
122 std::vector<hal::WorkDuration> mActualWorkDurations;
123 std::string mSessionName;
124 static int64_t sIDCounter;
125 // The most recent set of thread IDs
126 std::vector<int32_t> mLastThreadIDs;
127 std::optional<hal::SessionConfig> mSessionConfig;
128 // Tracing helpers
129 void traceThreads(std::vector<int32_t>& tids);
130 void tracePowerEfficient(bool powerEfficient);
131 void traceActualDuration(int64_t actualDuration);
132 void traceBatchSize(size_t batchSize);
133 void traceTargetDuration(int64_t targetDuration);
134 };
135
136 static std::shared_ptr<IHintManager>* gIHintManagerForTesting = nullptr;
137 static APerformanceHintManager* gHintManagerForTesting = nullptr;
138 // Start above the int32 range so we don't collide with config sessions
139 int64_t APerformanceHintSession::sIDCounter = INT32_MAX;
140
141 // ===================================== APerformanceHintManager implementation
APerformanceHintManager(std::shared_ptr<IHintManager> manager,int64_t preferredRateNanos)142 APerformanceHintManager::APerformanceHintManager(std::shared_ptr<IHintManager> manager,
143 int64_t preferredRateNanos)
144 : mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) {
145 static AIBinder_Class* tokenBinderClass =
146 AIBinder_Class_define("phm_token", tokenStubOnCreate, tokenStubOnDestroy,
147 tokenStubOnTransact);
148 mToken = ndk::SpAIBinder(AIBinder_new(tokenBinderClass, nullptr));
149 }
150
getInstance()151 APerformanceHintManager* APerformanceHintManager::getInstance() {
152 if (gHintManagerForTesting) return gHintManagerForTesting;
153 if (gIHintManagerForTesting) {
154 APerformanceHintManager* manager = create(*gIHintManagerForTesting);
155 gIHintManagerForTesting = nullptr;
156 return manager;
157 }
158 static APerformanceHintManager* instance = create(nullptr);
159 return instance;
160 }
161
create(std::shared_ptr<IHintManager> manager)162 APerformanceHintManager* APerformanceHintManager::create(std::shared_ptr<IHintManager> manager) {
163 if (!manager) {
164 manager = IHintManager::fromBinder(
165 ndk::SpAIBinder(AServiceManager_waitForService("performance_hint")));
166 }
167 if (manager == nullptr) {
168 ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__);
169 return nullptr;
170 }
171 int64_t preferredRateNanos = -1L;
172 ndk::ScopedAStatus ret = manager->getHintSessionPreferredRate(&preferredRateNanos);
173 if (!ret.isOk()) {
174 ALOGE("%s: PerformanceHint cannot get preferred rate. %s", __FUNCTION__, ret.getMessage());
175 return nullptr;
176 }
177 if (preferredRateNanos <= 0) {
178 preferredRateNanos = -1L;
179 }
180 return new APerformanceHintManager(std::move(manager), preferredRateNanos);
181 }
182
createSession(const int32_t * threadIds,size_t size,int64_t initialTargetWorkDurationNanos,hal::SessionTag tag)183 APerformanceHintSession* APerformanceHintManager::createSession(
184 const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos,
185 hal::SessionTag tag) {
186 std::vector<int32_t> tids(threadIds, threadIds + size);
187 std::shared_ptr<IHintSession> session;
188 ndk::ScopedAStatus ret;
189 std::optional<hal::SessionConfig> sessionConfig;
190 ret = mHintManager->createHintSessionWithConfig(mToken, tids, initialTargetWorkDurationNanos,
191 tag, &sessionConfig, &session);
192
193 if (!ret.isOk() || !session) {
194 return nullptr;
195 }
196 auto out = new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos,
197 initialTargetWorkDurationNanos, sessionConfig);
198 std::scoped_lock lock(sHintMutex);
199 out->traceThreads(tids);
200 out->traceTargetDuration(initialTargetWorkDurationNanos);
201 out->tracePowerEfficient(false);
202 return out;
203 }
204
getPreferredRateNanos() const205 int64_t APerformanceHintManager::getPreferredRateNanos() const {
206 return mPreferredRateNanos;
207 }
208
209 // ===================================== APerformanceHintSession implementation
210
APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,std::shared_ptr<IHintSession> session,int64_t preferredRateNanos,int64_t targetDurationNanos,std::optional<hal::SessionConfig> sessionConfig)211 APerformanceHintSession::APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
212 std::shared_ptr<IHintSession> session,
213 int64_t preferredRateNanos,
214 int64_t targetDurationNanos,
215 std::optional<hal::SessionConfig> sessionConfig)
216 : mHintManager(hintManager),
217 mHintSession(std::move(session)),
218 mPreferredRateNanos(preferredRateNanos),
219 mTargetDurationNanos(targetDurationNanos),
220 mFirstTargetMetTimestamp(0),
221 mLastTargetMetTimestamp(0),
222 mSessionConfig(sessionConfig) {
223 if (sessionConfig->id > INT32_MAX) {
224 ALOGE("Session ID too large, must fit 32-bit integer");
225 }
226 std::scoped_lock lock(sHintMutex);
227 constexpr int numEnums =
228 ndk::enum_range<hal::SessionHint>().end() - ndk::enum_range<hal::SessionHint>().begin();
229 mLastHintSentTimestamp = std::vector<int64_t>(numEnums, 0);
230 int64_t traceId = sessionConfig.has_value() ? sessionConfig->id : ++sIDCounter;
231 mSessionName = android::base::StringPrintf("ADPF Session %" PRId64, traceId);
232 }
233
~APerformanceHintSession()234 APerformanceHintSession::~APerformanceHintSession() {
235 ndk::ScopedAStatus ret = mHintSession->close();
236 if (!ret.isOk()) {
237 ALOGE("%s: HintSession close failed: %s", __FUNCTION__, ret.getMessage());
238 }
239 }
240
updateTargetWorkDuration(int64_t targetDurationNanos)241 int APerformanceHintSession::updateTargetWorkDuration(int64_t targetDurationNanos) {
242 if (targetDurationNanos <= 0) {
243 ALOGE("%s: targetDurationNanos must be positive", __FUNCTION__);
244 return EINVAL;
245 }
246 ndk::ScopedAStatus ret = mHintSession->updateTargetWorkDuration(targetDurationNanos);
247 if (!ret.isOk()) {
248 ALOGE("%s: HintSession updateTargetWorkDuration failed: %s", __FUNCTION__,
249 ret.getMessage());
250 return EPIPE;
251 }
252 std::scoped_lock lock(sHintMutex);
253 mTargetDurationNanos = targetDurationNanos;
254 /**
255 * Most of the workload is target_duration dependent, so now clear the cached samples
256 * as they are most likely obsolete.
257 */
258 mActualWorkDurations.clear();
259 traceBatchSize(0);
260 traceTargetDuration(targetDurationNanos);
261 mFirstTargetMetTimestamp = 0;
262 mLastTargetMetTimestamp = 0;
263 return 0;
264 }
265
reportActualWorkDuration(int64_t actualDurationNanos)266 int APerformanceHintSession::reportActualWorkDuration(int64_t actualDurationNanos) {
267 hal::WorkDuration workDuration{.durationNanos = actualDurationNanos,
268 .workPeriodStartTimestampNanos = 0,
269 .cpuDurationNanos = actualDurationNanos,
270 .gpuDurationNanos = 0};
271
272 return reportActualWorkDurationInternal(static_cast<AWorkDuration*>(&workDuration));
273 }
274
sendHint(SessionHint hint)275 int APerformanceHintSession::sendHint(SessionHint hint) {
276 std::scoped_lock lock(sHintMutex);
277 if (hint < 0 || hint >= static_cast<int32_t>(mLastHintSentTimestamp.size())) {
278 ALOGE("%s: invalid session hint %d", __FUNCTION__, hint);
279 return EINVAL;
280 }
281 int64_t now = uptimeNanos();
282
283 // Limit sendHint to a pre-detemined rate for safety
284 if (now < (mLastHintSentTimestamp[hint] + SEND_HINT_TIMEOUT)) {
285 return 0;
286 }
287
288 ndk::ScopedAStatus ret = mHintSession->sendHint(hint);
289
290 if (!ret.isOk()) {
291 ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.getMessage());
292 return EPIPE;
293 }
294 mLastHintSentTimestamp[hint] = now;
295 return 0;
296 }
297
setThreads(const int32_t * threadIds,size_t size)298 int APerformanceHintSession::setThreads(const int32_t* threadIds, size_t size) {
299 if (size == 0) {
300 ALOGE("%s: the list of thread ids must not be empty.", __FUNCTION__);
301 return EINVAL;
302 }
303 std::vector<int32_t> tids(threadIds, threadIds + size);
304 ndk::ScopedAStatus ret = mHintManager->setHintSessionThreads(mHintSession, tids);
305 if (!ret.isOk()) {
306 ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage());
307 if (ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT) {
308 return EINVAL;
309 } else if (ret.getExceptionCode() == EX_SECURITY) {
310 return EPERM;
311 }
312 return EPIPE;
313 }
314
315 std::scoped_lock lock(sHintMutex);
316 traceThreads(tids);
317
318 return 0;
319 }
320
getThreadIds(int32_t * const threadIds,size_t * size)321 int APerformanceHintSession::getThreadIds(int32_t* const threadIds, size_t* size) {
322 std::vector<int32_t> tids;
323 ndk::ScopedAStatus ret = mHintManager->getHintSessionThreadIds(mHintSession, &tids);
324 if (!ret.isOk()) {
325 ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage());
326 return EPIPE;
327 }
328
329 // When threadIds is nullptr, this is the first call to determine the size
330 // of the thread ids list.
331 if (threadIds == nullptr) {
332 *size = tids.size();
333 return 0;
334 }
335
336 // Second call to return the actual list of thread ids.
337 *size = tids.size();
338 for (size_t i = 0; i < *size; ++i) {
339 threadIds[i] = tids[i];
340 }
341 return 0;
342 }
343
setPreferPowerEfficiency(bool enabled)344 int APerformanceHintSession::setPreferPowerEfficiency(bool enabled) {
345 ndk::ScopedAStatus ret =
346 mHintSession->setMode(static_cast<int32_t>(hal::SessionMode::POWER_EFFICIENCY),
347 enabled);
348
349 if (!ret.isOk()) {
350 ALOGE("%s: HintSession setPreferPowerEfficiency failed: %s", __FUNCTION__,
351 ret.getMessage());
352 return EPIPE;
353 }
354 std::scoped_lock lock(sHintMutex);
355 tracePowerEfficient(enabled);
356 return OK;
357 }
358
reportActualWorkDuration(AWorkDuration * workDuration)359 int APerformanceHintSession::reportActualWorkDuration(AWorkDuration* workDuration) {
360 return reportActualWorkDurationInternal(workDuration);
361 }
362
reportActualWorkDurationInternal(AWorkDuration * workDuration)363 int APerformanceHintSession::reportActualWorkDurationInternal(AWorkDuration* workDuration) {
364 int64_t actualTotalDurationNanos = workDuration->durationNanos;
365 int64_t now = uptimeNanos();
366 workDuration->timeStampNanos = now;
367 std::scoped_lock lock(sHintMutex);
368 traceActualDuration(workDuration->durationNanos);
369 mActualWorkDurations.push_back(std::move(*workDuration));
370
371 if (actualTotalDurationNanos >= mTargetDurationNanos) {
372 // Reset timestamps if we are equal or over the target.
373 mFirstTargetMetTimestamp = 0;
374 } else {
375 // Set mFirstTargetMetTimestamp for first time meeting target.
376 if (!mFirstTargetMetTimestamp || !mLastTargetMetTimestamp ||
377 (now - mLastTargetMetTimestamp > 2 * mPreferredRateNanos)) {
378 mFirstTargetMetTimestamp = now;
379 }
380 /**
381 * Rate limit the change if the update is over mPreferredRateNanos since first
382 * meeting target and less than mPreferredRateNanos since last meeting target.
383 */
384 if (now - mFirstTargetMetTimestamp > mPreferredRateNanos &&
385 now - mLastTargetMetTimestamp <= mPreferredRateNanos) {
386 traceBatchSize(mActualWorkDurations.size());
387 return 0;
388 }
389 mLastTargetMetTimestamp = now;
390 }
391
392 ndk::ScopedAStatus ret = mHintSession->reportActualWorkDuration2(mActualWorkDurations);
393 if (!ret.isOk()) {
394 ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__,
395 ret.getMessage());
396 mFirstTargetMetTimestamp = 0;
397 mLastTargetMetTimestamp = 0;
398 traceBatchSize(mActualWorkDurations.size());
399 return ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT ? EINVAL : EPIPE;
400 }
401 mActualWorkDurations.clear();
402 traceBatchSize(0);
403
404 return 0;
405 }
406 // ===================================== Tracing helpers
407
traceThreads(std::vector<int32_t> & tids)408 void APerformanceHintSession::traceThreads(std::vector<int32_t>& tids) {
409 std::set<int32_t> tidSet{tids.begin(), tids.end()};
410
411 // Disable old TID tracing
412 for (int32_t tid : mLastThreadIDs) {
413 if (!tidSet.count(tid)) {
414 std::string traceName =
415 android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
416 ATrace_setCounter(traceName.c_str(), 0);
417 }
418 }
419
420 // Add new TID tracing
421 for (int32_t tid : tids) {
422 std::string traceName =
423 android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
424 ATrace_setCounter(traceName.c_str(), 1);
425 }
426
427 mLastThreadIDs = std::move(tids);
428 }
429
tracePowerEfficient(bool powerEfficient)430 void APerformanceHintSession::tracePowerEfficient(bool powerEfficient) {
431 ATrace_setCounter((mSessionName + " power efficiency mode").c_str(), powerEfficient);
432 }
433
traceActualDuration(int64_t actualDuration)434 void APerformanceHintSession::traceActualDuration(int64_t actualDuration) {
435 ATrace_setCounter((mSessionName + " actual duration").c_str(), actualDuration);
436 }
437
traceBatchSize(size_t batchSize)438 void APerformanceHintSession::traceBatchSize(size_t batchSize) {
439 std::string traceName = StringPrintf("%s batch size", mSessionName.c_str());
440 ATrace_setCounter((mSessionName + " batch size").c_str(), batchSize);
441 }
442
traceTargetDuration(int64_t targetDuration)443 void APerformanceHintSession::traceTargetDuration(int64_t targetDuration) {
444 ATrace_setCounter((mSessionName + " target duration").c_str(), targetDuration);
445 }
446
447 // ===================================== C API
APerformanceHint_getManager()448 APerformanceHintManager* APerformanceHint_getManager() {
449 return APerformanceHintManager::getInstance();
450 }
451
452 #define VALIDATE_PTR(ptr) \
453 LOG_ALWAYS_FATAL_IF(ptr == nullptr, "%s: " #ptr " is nullptr", __FUNCTION__);
454
455 #define VALIDATE_INT(value, cmp) \
456 if (!(value cmp)) { \
457 ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
458 __FUNCTION__, value); \
459 return EINVAL; \
460 }
461
462 #define WARN_INT(value, cmp) \
463 if (!(value cmp)) { \
464 ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
465 __FUNCTION__, value); \
466 }
467
APerformanceHint_createSession(APerformanceHintManager * manager,const int32_t * threadIds,size_t size,int64_t initialTargetWorkDurationNanos)468 APerformanceHintSession* APerformanceHint_createSession(APerformanceHintManager* manager,
469 const int32_t* threadIds, size_t size,
470 int64_t initialTargetWorkDurationNanos) {
471 VALIDATE_PTR(manager)
472 VALIDATE_PTR(threadIds)
473 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos);
474 }
475
APerformanceHint_createSessionInternal(APerformanceHintManager * manager,const int32_t * threadIds,size_t size,int64_t initialTargetWorkDurationNanos,SessionTag tag)476 APerformanceHintSession* APerformanceHint_createSessionInternal(
477 APerformanceHintManager* manager, const int32_t* threadIds, size_t size,
478 int64_t initialTargetWorkDurationNanos, SessionTag tag) {
479 VALIDATE_PTR(manager)
480 VALIDATE_PTR(threadIds)
481 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos,
482 static_cast<hal::SessionTag>(tag));
483 }
484
APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager * manager)485 int64_t APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager* manager) {
486 VALIDATE_PTR(manager)
487 return manager->getPreferredRateNanos();
488 }
489
APerformanceHint_updateTargetWorkDuration(APerformanceHintSession * session,int64_t targetDurationNanos)490 int APerformanceHint_updateTargetWorkDuration(APerformanceHintSession* session,
491 int64_t targetDurationNanos) {
492 VALIDATE_PTR(session)
493 return session->updateTargetWorkDuration(targetDurationNanos);
494 }
495
APerformanceHint_reportActualWorkDuration(APerformanceHintSession * session,int64_t actualDurationNanos)496 int APerformanceHint_reportActualWorkDuration(APerformanceHintSession* session,
497 int64_t actualDurationNanos) {
498 VALIDATE_PTR(session)
499 VALIDATE_INT(actualDurationNanos, > 0)
500 return session->reportActualWorkDuration(actualDurationNanos);
501 }
502
APerformanceHint_closeSession(APerformanceHintSession * session)503 void APerformanceHint_closeSession(APerformanceHintSession* session) {
504 VALIDATE_PTR(session)
505 delete session;
506 }
507
APerformanceHint_sendHint(APerformanceHintSession * session,SessionHint hint)508 int APerformanceHint_sendHint(APerformanceHintSession* session, SessionHint hint) {
509 VALIDATE_PTR(session)
510 return session->sendHint(hint);
511 }
512
APerformanceHint_setThreads(APerformanceHintSession * session,const pid_t * threadIds,size_t size)513 int APerformanceHint_setThreads(APerformanceHintSession* session, const pid_t* threadIds,
514 size_t size) {
515 VALIDATE_PTR(session)
516 VALIDATE_PTR(threadIds)
517 return session->setThreads(threadIds, size);
518 }
519
APerformanceHint_getThreadIds(APerformanceHintSession * session,int32_t * const threadIds,size_t * const size)520 int APerformanceHint_getThreadIds(APerformanceHintSession* session, int32_t* const threadIds,
521 size_t* const size) {
522 VALIDATE_PTR(session)
523 return session->getThreadIds(threadIds, size);
524 }
525
APerformanceHint_setPreferPowerEfficiency(APerformanceHintSession * session,bool enabled)526 int APerformanceHint_setPreferPowerEfficiency(APerformanceHintSession* session, bool enabled) {
527 VALIDATE_PTR(session)
528 return session->setPreferPowerEfficiency(enabled);
529 }
530
APerformanceHint_reportActualWorkDuration2(APerformanceHintSession * session,AWorkDuration * workDurationPtr)531 int APerformanceHint_reportActualWorkDuration2(APerformanceHintSession* session,
532 AWorkDuration* workDurationPtr) {
533 VALIDATE_PTR(session)
534 VALIDATE_PTR(workDurationPtr)
535 VALIDATE_INT(workDurationPtr->durationNanos, > 0)
536 VALIDATE_INT(workDurationPtr->workPeriodStartTimestampNanos, > 0)
537 VALIDATE_INT(workDurationPtr->cpuDurationNanos, >= 0)
538 VALIDATE_INT(workDurationPtr->gpuDurationNanos, >= 0)
539 VALIDATE_INT(workDurationPtr->gpuDurationNanos + workDurationPtr->cpuDurationNanos, > 0)
540 return session->reportActualWorkDuration(workDurationPtr);
541 }
542
AWorkDuration_create()543 AWorkDuration* AWorkDuration_create() {
544 return new AWorkDuration();
545 }
546
AWorkDuration_release(AWorkDuration * aWorkDuration)547 void AWorkDuration_release(AWorkDuration* aWorkDuration) {
548 VALIDATE_PTR(aWorkDuration)
549 delete aWorkDuration;
550 }
551
AWorkDuration_setActualTotalDurationNanos(AWorkDuration * aWorkDuration,int64_t actualTotalDurationNanos)552 void AWorkDuration_setActualTotalDurationNanos(AWorkDuration* aWorkDuration,
553 int64_t actualTotalDurationNanos) {
554 VALIDATE_PTR(aWorkDuration)
555 WARN_INT(actualTotalDurationNanos, > 0)
556 aWorkDuration->durationNanos = actualTotalDurationNanos;
557 }
558
AWorkDuration_setWorkPeriodStartTimestampNanos(AWorkDuration * aWorkDuration,int64_t workPeriodStartTimestampNanos)559 void AWorkDuration_setWorkPeriodStartTimestampNanos(AWorkDuration* aWorkDuration,
560 int64_t workPeriodStartTimestampNanos) {
561 VALIDATE_PTR(aWorkDuration)
562 WARN_INT(workPeriodStartTimestampNanos, > 0)
563 aWorkDuration->workPeriodStartTimestampNanos = workPeriodStartTimestampNanos;
564 }
565
AWorkDuration_setActualCpuDurationNanos(AWorkDuration * aWorkDuration,int64_t actualCpuDurationNanos)566 void AWorkDuration_setActualCpuDurationNanos(AWorkDuration* aWorkDuration,
567 int64_t actualCpuDurationNanos) {
568 VALIDATE_PTR(aWorkDuration)
569 WARN_INT(actualCpuDurationNanos, >= 0)
570 aWorkDuration->cpuDurationNanos = actualCpuDurationNanos;
571 }
572
AWorkDuration_setActualGpuDurationNanos(AWorkDuration * aWorkDuration,int64_t actualGpuDurationNanos)573 void AWorkDuration_setActualGpuDurationNanos(AWorkDuration* aWorkDuration,
574 int64_t actualGpuDurationNanos) {
575 VALIDATE_PTR(aWorkDuration)
576 WARN_INT(actualGpuDurationNanos, >= 0)
577 aWorkDuration->gpuDurationNanos = actualGpuDurationNanos;
578 }
579
APerformanceHint_setIHintManagerForTesting(void * iManager)580 void APerformanceHint_setIHintManagerForTesting(void* iManager) {
581 delete gHintManagerForTesting;
582 gHintManagerForTesting = nullptr;
583 gIHintManagerForTesting = static_cast<std::shared_ptr<IHintManager>*>(iManager);
584 }
585