1 /*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include <android/native_window_jni.h>
17 #include <android/performance_hint.h>
18 #include <android/surface_control_jni.h>
19 #include <errno.h>
20 #include <jni.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24
25 #include <future>
26 #include <list>
27 #include <sstream>
28 #include <vector>
29
toJString(JNIEnv * env,const char * c_str)30 static jstring toJString(JNIEnv *env, const char* c_str) {
31 return env->NewStringUTF(c_str);
32 }
33
34 constexpr int64_t DEFAULT_TARGET_NS = 16666666L;
35
36 #define CHECK_SESSION_RETURN(retval, session, situation) \
37 if (retval != 0 || session == nullptr) { \
38 return toJString(env, \
39 std::format(situation " returned status: {}{}", retval, \
40 session == nullptr ? " with a null session" : "") \
41 .c_str()); \
42 }
43
44 template <class T, void (*D)(T*)>
wrapSP(T * incoming)45 std::shared_ptr<T> wrapSP(T* incoming) {
46 return incoming == nullptr ? nullptr : std::shared_ptr<T>(incoming, [](T* ptr) { D(ptr); });
47 }
48
49 // Preferable to template specialization bc if we wrap something unsupported, it's more obvious
50 constexpr auto&& wrapSession = wrapSP<APerformanceHintSession, APerformanceHint_closeSession>;
51 constexpr auto&& wrapConfig = wrapSP<ASessionCreationConfig, ASessionCreationConfig_release>;
52 constexpr auto&& wrapWorkDuration = wrapSP<AWorkDuration, AWorkDuration_release>;
53 constexpr auto&& wrapSurfaceControl = wrapSP<ASurfaceControl, ASurfaceControl_release>;
54 constexpr auto&& wrapNativeWindow = wrapSP<ANativeWindow, ANativeWindow_release>;
55
createSession(APerformanceHintManager * manager)56 std::shared_ptr<APerformanceHintSession> createSession(APerformanceHintManager* manager) {
57 int32_t pid = getpid();
58 return wrapSession(APerformanceHint_createSession(manager, &pid, 1u, DEFAULT_TARGET_NS));
59 }
60
createSessionWithConfig(APerformanceHintManager * manager,std::shared_ptr<ASessionCreationConfig> config,int * out)61 std::shared_ptr<APerformanceHintSession> createSessionWithConfig(
62 APerformanceHintManager* manager, std::shared_ptr<ASessionCreationConfig> config,
63 int* out) {
64 APerformanceHintSession* sessionOut;
65 *out = APerformanceHint_createSessionUsingConfig(manager, config.get(), &sessionOut);
66 return wrapSession(sessionOut);
67 }
68
createConfig()69 std::shared_ptr<ASessionCreationConfig> createConfig() {
70 return wrapConfig(ASessionCreationConfig_create());
71 }
72
73 struct WorkDurationCreator {
74 int64_t workPeriodStart;
75 int64_t totalDuration;
76 int64_t cpuDuration;
77 int64_t gpuDuration;
78 };
79
80 struct ConfigCreator {
81 std::vector<int32_t> tids{getpid()};
82 int64_t targetDuration = DEFAULT_TARGET_NS;
83 bool powerEfficient = false;
84 bool graphicsPipeline = false;
85 std::vector<ANativeWindow*> nativeWindows{};
86 std::vector<ASurfaceControl*> surfaceControls{};
87 bool autoCpu = false;
88 bool autoGpu = false;
89 };
90
91 struct SupportHelper {
92 bool hintSessions : 1;
93 bool powerEfficiency : 1;
94 bool bindToSurface : 1;
95 bool graphicsPipeline : 1;
96 bool autoCpu : 1;
97 bool autoGpu : 1;
98 };
99
getSupportHelper()100 SupportHelper getSupportHelper() {
101 return {
102 .hintSessions = APerformanceHint_isFeatureSupported(APERF_HINT_SESSIONS),
103 .powerEfficiency = APerformanceHint_isFeatureSupported(APERF_HINT_POWER_EFFICIENCY),
104 .bindToSurface = APerformanceHint_isFeatureSupported(APERF_HINT_SURFACE_BINDING),
105 .graphicsPipeline = APerformanceHint_isFeatureSupported(APERF_HINT_GRAPHICS_PIPELINE),
106 .autoCpu = APerformanceHint_isFeatureSupported(APERF_HINT_AUTO_CPU),
107 .autoGpu = APerformanceHint_isFeatureSupported(APERF_HINT_AUTO_GPU),
108 };
109 }
110
configFromCreator(ConfigCreator && creator)111 std::shared_ptr<ASessionCreationConfig> configFromCreator(ConfigCreator&& creator) {
112 auto config = createConfig();
113
114 ASessionCreationConfig_setTids(config.get(), creator.tids.data(), creator.tids.size());
115 ASessionCreationConfig_setTargetWorkDurationNanos(config.get(), creator.targetDuration);
116 ASessionCreationConfig_setPreferPowerEfficiency(config.get(), creator.powerEfficient);
117 ASessionCreationConfig_setGraphicsPipeline(config.get(), creator.graphicsPipeline);
118 ASessionCreationConfig_setNativeSurfaces(config.get(),
119 creator.nativeWindows.size() > 0
120 ? creator.nativeWindows.data()
121 : nullptr,
122 creator.nativeWindows.size(),
123 creator.surfaceControls.size() > 0
124 ? creator.surfaceControls.data()
125 : nullptr,
126 creator.surfaceControls.size());
127 ASessionCreationConfig_setUseAutoTiming(config.get(), creator.autoCpu, creator.autoGpu);
128 return config;
129 }
130
createWorkDuration(WorkDurationCreator creator)131 static std::shared_ptr<AWorkDuration> createWorkDuration(WorkDurationCreator creator) {
132 AWorkDuration* out = AWorkDuration_create();
133 AWorkDuration_setWorkPeriodStartTimestampNanos(out, creator.workPeriodStart);
134 AWorkDuration_setActualTotalDurationNanos(out, creator.totalDuration);
135 AWorkDuration_setActualCpuDurationNanos(out, creator.cpuDuration);
136 AWorkDuration_setActualGpuDurationNanos(out, creator.gpuDuration);
137 return wrapWorkDuration(out);
138 }
139
nativeGetSessionsAreSupported()140 static jboolean nativeGetSessionsAreSupported() {
141 return APerformanceHint_isFeatureSupported(APERF_HINT_SESSIONS);
142 }
143
nativeTestCreateHintSession(JNIEnv * env,jobject)144 static jstring nativeTestCreateHintSession(JNIEnv *env, jobject) {
145 APerformanceHintManager* manager = APerformanceHint_getManager();
146 if (!manager) return toJString(env, "null manager");
147 auto a = createSession(manager);
148 auto b = createSession(manager);
149 if (a == nullptr) {
150 return toJString(env, "a is null");
151 } else if (b == nullptr) {
152 return toJString(env, "b is null");
153 } else if (a.get() == b.get()) {
154 return toJString(env, "a and b matches");
155 }
156 return nullptr;
157 }
158
nativeTestCreateHintSessionUsingConfig(JNIEnv * env,jobject)159 static jstring nativeTestCreateHintSessionUsingConfig(JNIEnv* env, jobject) {
160 APerformanceHintManager* manager = APerformanceHint_getManager();
161 if (!manager) return toJString(env, "null manager");
162 auto config = configFromCreator({});
163 if (config == nullptr) {
164 return toJString(env, "config is null");
165 }
166
167 int returnVal = 0;
168 auto a = createSessionWithConfig(manager, config, &returnVal);
169 if (returnVal != 0) {
170 return toJString(env,
171 std::format("Session creation failed with status: {}", returnVal).c_str());
172 }
173
174 auto b = createSessionWithConfig(manager, config, &returnVal);
175 if (a == nullptr) {
176 return toJString(env, "a is null");
177 } else if (b == nullptr) {
178 return toJString(env, "b is null");
179 } else if (a.get() == b.get()) {
180 return toJString(env, "a and b matches");
181 }
182 return nullptr;
183 }
184
nativeTestGetPreferredUpdateRateNanos(JNIEnv * env,jobject)185 static jstring nativeTestGetPreferredUpdateRateNanos(JNIEnv *env, jobject) {
186 APerformanceHintManager* manager = APerformanceHint_getManager();
187 if (!manager) return toJString(env, "null manager");
188 auto session = createSession(manager);
189 if (session != nullptr) {
190 bool positive = APerformanceHint_getPreferredUpdateRateNanos(manager) > 0;
191 if (!positive)
192 return toJString(env, "preferred rate is not positive");
193 } else {
194 if (APerformanceHint_getPreferredUpdateRateNanos(manager) != -1)
195 return toJString(env, "preferred rate is not -1");
196 }
197 return nullptr;
198 }
199
nativeUpdateTargetWorkDuration(JNIEnv * env,jobject)200 static jstring nativeUpdateTargetWorkDuration(JNIEnv *env, jobject) {
201 APerformanceHintManager* manager = APerformanceHint_getManager();
202 if (!manager) return toJString(env, "null manager");
203 auto session = createSession(manager);
204 if (session == nullptr) return nullptr;
205
206 int result = APerformanceHint_updateTargetWorkDuration(session.get(), 100);
207 if (result != 0) {
208 return toJString(env, "updateTargetWorkDuration did not return 0");
209 }
210 return nullptr;
211 }
212
nativeUpdateTargetWorkDurationWithNegativeDuration(JNIEnv * env,jobject)213 static jstring nativeUpdateTargetWorkDurationWithNegativeDuration(JNIEnv *env, jobject) {
214 APerformanceHintManager* manager = APerformanceHint_getManager();
215 if (!manager) return toJString(env, "null manager");
216 auto session = createSession(manager);
217 if (session == nullptr) return nullptr;
218
219 int result = APerformanceHint_updateTargetWorkDuration(session.get(), -1);
220 if (result != EINVAL) {
221 return toJString(env, "updateTargetWorkDuration did not return EINVAL");
222 }
223 return nullptr;
224 }
225
nativeReportActualWorkDuration(JNIEnv * env,jobject)226 static jstring nativeReportActualWorkDuration(JNIEnv *env, jobject) {
227 APerformanceHintManager* manager = APerformanceHint_getManager();
228 if (!manager) return toJString(env, "null manager");
229 auto session = createSession(manager);
230 if (session == nullptr) return nullptr;
231
232 int result = APerformanceHint_reportActualWorkDuration(session.get(), 100);
233 if (result != 0) {
234 return toJString(env, "reportActualWorkDuration(100) did not return 0");
235 }
236
237 result = APerformanceHint_reportActualWorkDuration(session.get(), 1);
238 if (result != 0) {
239 return toJString(env, "reportActualWorkDuration(1) did not return 0");
240 }
241
242 result = APerformanceHint_reportActualWorkDuration(session.get(), 100);
243 if (result != 0) {
244 return toJString(env, "reportActualWorkDuration(100) did not return 0");
245 }
246
247 result = APerformanceHint_reportActualWorkDuration(session.get(), 1000);
248 if (result != 0) {
249 return toJString(env, "reportActualWorkDuration(1000) did not return 0");
250 }
251
252 return nullptr;
253 }
254
nativeReportActualWorkDurationWithIllegalArgument(JNIEnv * env,jobject)255 static jstring nativeReportActualWorkDurationWithIllegalArgument(JNIEnv *env, jobject) {
256 APerformanceHintManager* manager = APerformanceHint_getManager();
257 if (!manager) return toJString(env, "null manager");
258 auto session = createSession(manager);
259 if (session == nullptr) return nullptr;
260
261 int result = APerformanceHint_reportActualWorkDuration(session.get(), -1);
262 if (result != EINVAL) {
263 return toJString(env, "reportActualWorkDuration did not return EINVAL");
264 }
265 return nullptr;
266 }
267
nativeTestSetThreadsWithInvalidTid(JNIEnv * env,jobject)268 static jstring nativeTestSetThreadsWithInvalidTid(JNIEnv* env, jobject) {
269 APerformanceHintManager* manager = APerformanceHint_getManager();
270 if (!manager) {
271 return toJString(env, "null manager");
272 }
273 auto session = createSession(manager);
274 if (session == nullptr) {
275 return nullptr;
276 }
277
278 std::vector<pid_t> tids;
279 tids.push_back(2);
280 int result = APerformanceHint_setThreads(session.get(), tids.data(), 1);
281 if (result != EPERM) {
282 return toJString(env, "setThreads did not return EPERM");
283 }
284 return nullptr;
285 }
286
287
nativeSetPreferPowerEfficiency(JNIEnv * env,jobject)288 static jstring nativeSetPreferPowerEfficiency(JNIEnv* env, jobject) {
289 APerformanceHintManager* manager = APerformanceHint_getManager();
290 if (!manager) return toJString(env, "null manager");
291 auto session = createSession(manager);
292 if (session == nullptr) return nullptr;
293
294 int result = APerformanceHint_setPreferPowerEfficiency(session.get(), false);
295 if (result != 0) {
296 return toJString(env, "setPreferPowerEfficiency(false) did not return 0");
297 }
298
299 result = APerformanceHint_setPreferPowerEfficiency(session.get(), true);
300 if (result != 0) {
301 return toJString(env, "setPreferPowerEfficiency(true) did not return 0");
302 }
303
304 result = APerformanceHint_setPreferPowerEfficiency(session.get(), true);
305 if (result != 0) {
306 return toJString(env, "setPreferPowerEfficiency(true) did not return 0");
307 }
308 return nullptr;
309 }
310
nativeTestReportActualWorkDuration2(JNIEnv * env,jobject)311 static jstring nativeTestReportActualWorkDuration2(JNIEnv* env, jobject) {
312 APerformanceHintManager* manager = APerformanceHint_getManager();
313 if (!manager) return toJString(env, "null manager");
314 auto session = createSession(manager);
315 if (session == nullptr) return nullptr;
316
317 std::vector<WorkDurationCreator> testCases = {
318 {
319 .workPeriodStart = 1000,
320 .totalDuration = 14,
321 .cpuDuration = 11,
322 .gpuDuration = 8
323 },
324 {
325 .workPeriodStart = 1016,
326 .totalDuration = 14,
327 .cpuDuration = 12,
328 .gpuDuration = 4
329 },
330 {
331 .workPeriodStart = 1016,
332 .totalDuration = 14,
333 .cpuDuration = 12,
334 .gpuDuration = 4
335 },
336 {
337 .workPeriodStart = 900,
338 .totalDuration = 20,
339 .cpuDuration = 20,
340 .gpuDuration = 0
341 },
342 {
343 .workPeriodStart = 800,
344 .totalDuration = 20,
345 .cpuDuration = 0,
346 .gpuDuration = 20
347 }
348 };
349
350 for (auto && testCase : testCases) {
351 auto&& testObj = createWorkDuration(testCase);
352 int result = APerformanceHint_reportActualWorkDuration2(session.get(), testObj.get());
353 if (result != 0) {
354 std::stringstream stream;
355 stream << "APerformanceHint_reportActualWorkDuration2({"
356 << "workPeriodStartTimestampNanos = " << testCase.workPeriodStart << ", "
357 << "actualTotalDurationNanos = " << testCase.totalDuration << ", "
358 << "actualCpuDurationNanos = " << testCase.cpuDuration << ", "
359 << "actualGpuDurationNanos = " << testCase.gpuDuration << "}) did not return 0";
360 return toJString(env, stream.str().c_str());
361 }
362 }
363
364 return nullptr;
365 }
366
nativeTestReportActualWorkDuration2WithIllegalArgument(JNIEnv * env,jobject)367 static jstring nativeTestReportActualWorkDuration2WithIllegalArgument(JNIEnv* env, jobject) {
368 APerformanceHintManager* manager = APerformanceHint_getManager();
369 if (!manager) return toJString(env, "null manager");
370 auto session = createSession(manager);
371 if (session == nullptr) return nullptr;
372
373 std::vector<WorkDurationCreator> testCases = {
374 {
375 .workPeriodStart = -1,
376 .totalDuration = 14,
377 .cpuDuration = 11,
378 .gpuDuration = 8
379 },
380 {
381 .workPeriodStart = 1000,
382 .totalDuration = -1,
383 .cpuDuration = 11,
384 .gpuDuration = 8
385 },
386 {
387 .workPeriodStart = 1000,
388 .totalDuration = 14,
389 .cpuDuration = -1,
390 .gpuDuration = 8
391 },
392 {
393 .workPeriodStart = 1000,
394 .totalDuration = 14,
395 .cpuDuration = 11,
396 .gpuDuration = -1
397 },
398 {
399 .workPeriodStart = 1000,
400 .totalDuration = 14,
401 .cpuDuration = 0,
402 .gpuDuration = 0
403 }
404 };
405
406 for (auto && testCase : testCases) {
407 auto&& testObj = createWorkDuration(testCase);
408 int result = APerformanceHint_reportActualWorkDuration2(session.get(), testObj.get());
409 if (result != EINVAL) {
410 std::stringstream stream;
411 stream << "APerformanceHint_reportActualWorkDuration2({"
412 << "workPeriodStartTimestampNanos = " << testCase.workPeriodStart << ", "
413 << "actualTotalDurationNanos = " << testCase.totalDuration << ", "
414 << "actualCpuDurationNanos = " << testCase.cpuDuration << ", "
415 << "actualGpuDurationNanos = " << testCase.gpuDuration
416 << "}) did not return EINVAL";
417 return toJString(env, stream.str().c_str());
418 }
419 }
420
421 return nullptr;
422 }
423
nativeTestLoadHints(JNIEnv * env,jobject)424 static jstring nativeTestLoadHints(JNIEnv* env, jobject) {
425 APerformanceHintManager* manager = APerformanceHint_getManager();
426 if (!manager) return toJString(env, "null manager");
427 auto session = createSession(manager);
428 if (session == nullptr) return nullptr;
429
430 int result = APerformanceHint_notifyWorkloadIncrease(session.get(), true, false, "CTS hint 1");
431 if (result != 0 && result != EBUSY) {
432 return toJString(env,
433 std::format("notifyWorkloadIncrease(true, false) returned {}", result)
434 .c_str());
435 }
436
437 result = APerformanceHint_notifyWorkloadReset(session.get(), false, true, "CTS hint 2");
438 if (result != 0 && result != EBUSY) {
439 return toJString(env,
440 std::format("notifyWorkloadReset(false, true) returned {}", result)
441 .c_str());
442 }
443
444 result = APerformanceHint_notifyWorkloadIncrease(session.get(), true, true, "CTS hint 3");
445 if (result != 0 && result != EBUSY) {
446 return toJString(env,
447 std::format("notifyWorkloadIncrease(true, true) returned {}", result)
448 .c_str());
449 }
450
451 result = APerformanceHint_notifyWorkloadIncrease(session.get(), false, false, "CTS hint 4");
452 if (result != 0 && result != EBUSY) {
453 return toJString(env,
454 std::format("notifyWorkloadIncrease(false, false) returned {}", result)
455 .c_str());
456 }
457
458 result = APerformanceHint_notifyWorkloadReset(session.get(), false, false, "CTS hint 5");
459 if (result != 0 && result != EBUSY) {
460 return toJString(env,
461 std::format("notifyWorkloadReset(false, false) returned {}", result)
462 .c_str());
463 }
464
465 result = APerformanceHint_notifyWorkloadSpike(session.get(), true, false, "CTS hint 6");
466 if (result != 0 && result != EBUSY) {
467 return toJString(env,
468 std::format("notifyWorkloadSpike(true, false) returned {}", result)
469 .c_str());
470 }
471
472 result = APerformanceHint_notifyWorkloadSpike(session.get(), false, true, "CTS hint 7");
473 if (result != 0 && result != EBUSY) {
474 return toJString(env,
475 std::format("notifyWorkloadSpike(false, true) returned {}", result)
476 .c_str());
477 }
478
479 result = APerformanceHint_notifyWorkloadSpike(session.get(), false, false, "CTS hint 8");
480 if (result != 0 && result != EBUSY) {
481 return toJString(env,
482 std::format("notifyWorkloadSpike(false, false) returned {}", result)
483 .c_str());
484 }
485
486 return nullptr;
487 }
488
nativeBorrowSessionFromJava(JNIEnv * env,jobject,jobject sessionObj)489 static jlong nativeBorrowSessionFromJava(JNIEnv* env, jobject, jobject sessionObj) {
490 APerformanceHintManager* manager = APerformanceHint_getManager();
491 if (!manager) return 0;
492
493 APerformanceHintSession* session = APerformanceHint_borrowSessionFromJava(env, sessionObj);
494
495 // Test a basic synchronous operation to ensure the session is valid.
496 int32_t pid = getpid();
497 int retval = APerformanceHint_setThreads(session, &pid, 1u);
498 if (retval != 0) {
499 return 0;
500 }
501
502 return reinterpret_cast<jlong>(session);
503 }
504
nativeTestCreateGraphicsPipelineSession(JNIEnv * env,jobject)505 static jstring nativeTestCreateGraphicsPipelineSession(JNIEnv* env, jobject) {
506 auto supportInfo = getSupportHelper();
507 if (!supportInfo.graphicsPipeline) {
508 return nullptr;
509 }
510
511 APerformanceHintManager* manager = APerformanceHint_getManager();
512 if (!manager) return toJString(env, "null manager");
513
514 int errCode = 0;
515 const int count = APerformanceHint_getMaxGraphicsPipelineThreadsCount(manager);
516 auto config = configFromCreator({.graphicsPipeline = true});
517 auto session = createSessionWithConfig(manager, config, &errCode);
518 CHECK_SESSION_RETURN(errCode, session, "Graphics pipeline session creation");
519
520 return nullptr;
521 }
522
nativeTestSetNativeSurfaces(JNIEnv * env,jobject,jobject surfaceControlFromJava,jobject surfaceFromJava)523 static jstring nativeTestSetNativeSurfaces(JNIEnv* env, jobject, jobject surfaceControlFromJava,
524 jobject surfaceFromJava) {
525 auto supportInfo = getSupportHelper();
526 if (!supportInfo.bindToSurface) {
527 return nullptr;
528 }
529
530 APerformanceHintManager* manager = APerformanceHint_getManager();
531 if (!manager) return toJString(env, "null manager");
532
533 int errCode = 0;
534
535 auto surfaceControl = wrapSurfaceControl(ASurfaceControl_fromJava(env, surfaceControlFromJava));
536 auto nativeWindow = wrapNativeWindow(ANativeWindow_fromSurface(env, surfaceFromJava));
537
538 // Test native window session creation
539 auto nativeWindowConfig = configFromCreator({
540 .graphicsPipeline = true,
541 .nativeWindows = {nativeWindow.get()},
542 });
543 auto nativeWindowSession = createSessionWithConfig(manager, nativeWindowConfig, &errCode);
544 CHECK_SESSION_RETURN(errCode, nativeWindowSession, "Session creation with an ANativeWindow");
545
546 // Test surfaceControl session creation
547 auto surfaceControlConfig = configFromCreator({
548 .graphicsPipeline = true,
549 .surfaceControls = {surfaceControl.get()},
550 });
551 auto surfaceControlSession = createSessionWithConfig(manager, surfaceControlConfig, &errCode);
552 CHECK_SESSION_RETURN(errCode, nativeWindowSession, "Session creation with an ASurfaceControl");
553
554 // Test both
555 auto bothConfig = configFromCreator({
556 .graphicsPipeline = true,
557 .nativeWindows = {nativeWindow.get()},
558 .surfaceControls = {surfaceControl.get()},
559 });
560 auto bothSession = createSessionWithConfig(manager, bothConfig, &errCode);
561 CHECK_SESSION_RETURN(errCode, bothSession,
562 "Session creation with both ASurfaceControl and ANativeWindow");
563
564 // Test unsetting
565 errCode = APerformanceHint_setNativeSurfaces(bothSession.get(), nullptr, 0, nullptr, 0);
566 if (errCode != 0) {
567 return toJString(env,
568 std::format("Setting empty native surfaces failed with: {}", errCode)
569 .c_str());
570 }
571
572 // Test setting it back
573 ANativeWindow* windowArr[]{nativeWindow.get()};
574 ASurfaceControl* controlArr[]{surfaceControl.get()};
575
576 errCode = APerformanceHint_setNativeSurfaces(bothSession.get(), windowArr, 1, controlArr, 1);
577 if (errCode != 0) {
578 return toJString(env,
579 std::format("Setting native surfaces on re-used empty session failed "
580 "with: {}",
581 errCode)
582 .c_str());
583 }
584
585 // Create new empty sessions
586 auto unassociatedConfig = configFromCreator({
587 .graphicsPipeline = true,
588 });
589
590 auto unassociatedSession = createSessionWithConfig(manager, unassociatedConfig, &errCode);
591 CHECK_SESSION_RETURN(errCode, unassociatedSession, "Session creation while unassociated");
592
593 errCode = APerformanceHint_setNativeSurfaces(nativeWindowSession.get(), windowArr, 1,
594 controlArr, 1);
595 if (errCode != 0) {
596 return toJString(env,
597 std::format("Setting native surfaces on fresh unassociated session failed "
598 "with: {}",
599 errCode)
600 .c_str());
601 }
602
603 return nullptr;
604 }
605
nativeTestAutoSessionTiming(JNIEnv * env,jobject,jobject surfaceControlFromJava)606 static jstring nativeTestAutoSessionTiming(JNIEnv* env, jobject, jobject surfaceControlFromJava) {
607 APerformanceHintManager* manager = APerformanceHint_getManager();
608 if (!manager) return toJString(env, "null manager");
609
610 auto supportInfo = getSupportHelper();
611
612 std::string out;
613 int errCode;
614
615 auto surfaceControl = wrapSurfaceControl(ASurfaceControl_fromJava(env, surfaceControlFromJava));
616
617 if (supportInfo.autoCpu) {
618 // Create a surfaceControl-associated session for auto CPU
619 auto autoCpuSessionConfig = configFromCreator({
620 .graphicsPipeline = true,
621 .surfaceControls = {surfaceControl.get()},
622 .autoCpu = true,
623 });
624 if (autoCpuSessionConfig == nullptr) {
625 return toJString(env, out.c_str());
626 }
627
628 auto autoCpuSession = createSessionWithConfig(manager, autoCpuSessionConfig, &errCode);
629 CHECK_SESSION_RETURN(errCode, autoCpuSession, "Cpu auto session creation");
630 }
631
632 if (supportInfo.autoGpu) {
633 // Create a surfaceControl-associated session for auto GPU
634 auto autoGpuSessionConfig = configFromCreator({
635 .graphicsPipeline = true,
636 .surfaceControls = {surfaceControl.get()},
637 .autoGpu = true,
638 });
639 if (autoGpuSessionConfig == nullptr) {
640 return toJString(env, out.c_str());
641 }
642
643 auto autoGpuSession = createSessionWithConfig(manager, autoGpuSessionConfig, &errCode);
644 CHECK_SESSION_RETURN(errCode, autoGpuSession, "Gpu auto session creation");
645 }
646
647 if (supportInfo.autoCpu && supportInfo.autoGpu) {
648 // Create a surfaceControl-associated session for both
649 auto fullAutoSessionConfig = configFromCreator({
650 .graphicsPipeline = true,
651 .surfaceControls = {surfaceControl.get()},
652 .autoCpu = true,
653 .autoGpu = true,
654 });
655 if (fullAutoSessionConfig == nullptr) {
656 return toJString(env, out.c_str());
657 }
658
659 auto fullAutoSession = createSessionWithConfig(manager, fullAutoSessionConfig, &errCode);
660 CHECK_SESSION_RETURN(errCode, fullAutoSession, "Full auto session creation");
661 }
662
663 return nullptr;
664 }
665
nativeTestSupportChecking(JNIEnv * env,jobject)666 static jstring nativeTestSupportChecking(JNIEnv* env, jobject) {
667 union {
668 // This checks every single support enum
669 SupportHelper supportInfo = getSupportHelper();
670 int32_t supportInt;
671 };
672 if (!supportInfo.hintSessions) {
673 // If any mode other than hintSessions is enabled
674 if (supportInt & -2) {
675 return toJString(env, "Exposed support for session functionality but not for sessions");
676 }
677 } else if (supportInfo.autoCpu || supportInfo.autoGpu) {
678 if (!supportInfo.graphicsPipeline) {
679 return toJString(env,
680 "Exposed support for auto timing without support for graphics "
681 "pipelines");
682 } else if (!supportInfo.bindToSurface) {
683 return toJString(env,
684 "Exposed support for auto timing without support for native surface"
685 "binding");
686 }
687 }
688 return nullptr;
689 }
690
691 static JNINativeMethod gMethods[] = {
nativeGetSessionsAreSupported()692 {"nativeGetSessionsAreSupported", "()Z",
693 (void*)nativeGetSessionsAreSupported},
nativeTestCreateHintSession()694 {"nativeTestCreateHintSession", "()Ljava/lang/String;",
695 (void*)nativeTestCreateHintSession},
nativeTestCreateGraphicsPipelineSession()696 {"nativeTestCreateGraphicsPipelineSession", "()Ljava/lang/String;",
697 (void*)nativeTestCreateGraphicsPipelineSession},
nativeTestCreateHintSessionUsingConfig()698 {"nativeTestCreateHintSessionUsingConfig", "()Ljava/lang/String;",
699 (void*)nativeTestCreateHintSessionUsingConfig},
nativeTestGetPreferredUpdateRateNanos()700 {"nativeTestGetPreferredUpdateRateNanos", "()Ljava/lang/String;",
701 (void*)nativeTestGetPreferredUpdateRateNanos},
nativeUpdateTargetWorkDuration()702 {"nativeUpdateTargetWorkDuration", "()Ljava/lang/String;",
703 (void*)nativeUpdateTargetWorkDuration},
nativeUpdateTargetWorkDurationWithNegativeDuration()704 {"nativeUpdateTargetWorkDurationWithNegativeDuration", "()Ljava/lang/String;",
705 (void*)nativeUpdateTargetWorkDurationWithNegativeDuration},
nativeReportActualWorkDuration()706 {"nativeReportActualWorkDuration", "()Ljava/lang/String;",
707 (void*)nativeReportActualWorkDuration},
nativeReportActualWorkDurationWithIllegalArgument()708 {"nativeReportActualWorkDurationWithIllegalArgument", "()Ljava/lang/String;",
709 (void*)nativeReportActualWorkDurationWithIllegalArgument},
nativeTestSetThreadsWithInvalidTid()710 {"nativeTestSetThreadsWithInvalidTid", "()Ljava/lang/String;",
711 (void*)nativeTestSetThreadsWithInvalidTid},
nativeSetPreferPowerEfficiency()712 {"nativeSetPreferPowerEfficiency", "()Ljava/lang/String;",
713 (void*)nativeSetPreferPowerEfficiency},
nativeTestReportActualWorkDuration2()714 {"nativeTestReportActualWorkDuration2", "()Ljava/lang/String;",
715 (void*)nativeTestReportActualWorkDuration2},
nativeTestReportActualWorkDuration2WithIllegalArgument()716 {"nativeTestReportActualWorkDuration2WithIllegalArgument", "()Ljava/lang/String;",
717 (void*)nativeTestReportActualWorkDuration2WithIllegalArgument},
nativeTestLoadHints()718 {"nativeTestLoadHints", "()Ljava/lang/String;", (void*)nativeTestLoadHints},
nativeBorrowSessionFromJava(Landroid/os/PerformanceHintManager$Session;)719 {"nativeBorrowSessionFromJava", "(Landroid/os/PerformanceHintManager$Session;)J",
720 (void*)nativeBorrowSessionFromJava},
nativeTestSetNativeSurfaces(Landroid/view/SurfaceControl;Landroid/view/Surface;)721 {"nativeTestSetNativeSurfaces",
722 "(Landroid/view/SurfaceControl;Landroid/view/Surface;)Ljava/lang/String;",
723 (void*)nativeTestSetNativeSurfaces},
nativeTestAutoSessionTiming(Landroid/view/SurfaceControl;)724 {"nativeTestAutoSessionTiming", "(Landroid/view/SurfaceControl;)Ljava/lang/String;",
725 (void*)nativeTestAutoSessionTiming},
nativeTestSupportChecking()726 {"nativeTestSupportChecking", "()Ljava/lang/String;", (void*)nativeTestSupportChecking},
727 };
728
register_android_os_cts_PerformanceHintManagerTest(JNIEnv * env)729 int register_android_os_cts_PerformanceHintManagerTest(JNIEnv* env) {
730 jclass clazz = env->FindClass("android/os/cts/PerformanceHintManagerTest");
731
732 return env->RegisterNatives(clazz, gMethods, sizeof(gMethods) / sizeof(JNINativeMethod));
733 }
734