xref: /aosp_15_r20/cts/tests/tests/os/src/android/os/cts/PerformanceHintManagerTest.java (revision b7c941bb3fa97aba169d73cee0bed2de8ac964bf)
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 package android.os.cts;
18 
19 import static org.junit.Assert.assertArrayEquals;
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertNotEquals;
22 import static org.junit.Assert.assertNull;
23 import static org.junit.Assert.assertThrows;
24 import static org.junit.Assert.assertTrue;
25 import static org.junit.Assert.fail;
26 import static org.junit.Assume.assumeNotNull;
27 
28 import android.os.Flags;
29 import android.os.HandlerThread;
30 import android.os.PerformanceHintManager;
31 import android.os.PerformanceHintManager.Session;
32 import android.os.Process;
33 import android.os.WorkDuration;
34 import android.platform.test.annotations.AppModeSdkSandbox;
35 import android.platform.test.annotations.RequiresFlagsEnabled;
36 import android.platform.test.flag.junit.CheckFlagsRule;
37 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
38 import android.util.Log;
39 import android.view.Surface;
40 import android.view.SurfaceControl;
41 import android.view.cts.surfacevalidator.ASurfaceControlTestActivity;
42 
43 import androidx.test.InstrumentationRegistry;
44 import androidx.test.core.app.ActivityScenario;
45 import androidx.test.runner.AndroidJUnit4;
46 
47 import com.android.compatibility.common.util.ApiTest;
48 
49 import com.google.common.base.Strings;
50 
51 import org.junit.Before;
52 import org.junit.Rule;
53 import org.junit.Test;
54 import org.junit.runner.RunWith;
55 
56 import java.util.concurrent.CountDownLatch;
57 
58 @AppModeSdkSandbox(reason = "Allow test in the SDK sandbox (does not prevent other modes).")
59 @RunWith(AndroidJUnit4.class)
60 public class PerformanceHintManagerTest {
61     private static final String TAG = "PerformanceHintManagerTest";
62 
63     private final long DEFAULT_TARGET_NS = 16666666L;
64     private PerformanceHintManager mPerformanceHintManager;
65     private ASurfaceControlTestActivity mActivity;
66     private ActivityScenario<ASurfaceControlTestActivity> mScenario;
67     private SurfaceControl mSurfaceControl;
68 
makeSurfaceControl()69     private void makeSurfaceControl() {
70         mScenario = ActivityScenario.launch(ASurfaceControlTestActivity.class);
71         final CountDownLatch activityLatch = new CountDownLatch(1);
72 
73         mScenario.onActivity(
74                 activity -> {
75                     mActivity = activity;
76                     activityLatch.countDown();
77                     mSurfaceControl = new SurfaceControl.Builder()
78                             .setParent(mActivity.getSurfaceControl())
79                             .setName("testsurface")
80                             .setHidden(false)
81                             .build();
82                 });
83 
84         try {
85             activityLatch.await();
86         } catch (InterruptedException e) {
87             fail("Error while waiting for activity");
88         }
89     }
90 
91     @Rule
92     public final CheckFlagsRule mCheckFlagsRule =
93             DeviceFlagsValueProvider.createCheckFlagsRule();
94 
95     static {
96         System.loadLibrary("ctsos_jni");
97     }
98 
99     @Before
setUp()100     public void setUp() {
101         mPerformanceHintManager =
102                 InstrumentationRegistry.getInstrumentation().getContext().getSystemService(
103                         PerformanceHintManager.class);
104     }
105 
createSession()106     private Session createSession() {
107         return mPerformanceHintManager.createHintSession(
108                 new int[]{Process.myPid()}, DEFAULT_TARGET_NS);
109     }
110 
111     @Test
testCreateHintSession()112     public void testCreateHintSession() {
113         Session a = createSession();
114         Session b = createSession();
115         if (a == null) {
116             assertNull(b);
117         } else if (b == null) {
118             assertNull(a);
119         } else {
120             assertNotEquals(a, b);
121         }
122     }
123 
124     @Test
testNativeCreateHintSession()125     public void testNativeCreateHintSession() {
126         final String failureMessage = nativeTestCreateHintSession();
127         if (!Strings.isNullOrEmpty(failureMessage)) {
128             fail(failureMessage);
129         }
130     }
131 
132     @Test
testGetPreferredUpdateRateNanos()133     public void testGetPreferredUpdateRateNanos() {
134         if (createSession() != null) {
135             assertTrue(mPerformanceHintManager.getPreferredUpdateRateNanos() > 0);
136         } else {
137             assertEquals(-1, mPerformanceHintManager.getPreferredUpdateRateNanos());
138         }
139     }
140 
141     @Test
testNativeGetPreferredUpdateRateNanos()142     public void testNativeGetPreferredUpdateRateNanos() {
143         final String failureMessage = nativeTestGetPreferredUpdateRateNanos();
144         if (!Strings.isNullOrEmpty(failureMessage)) {
145             fail(failureMessage);
146         }
147     }
148 
149     @Test
testUpdateTargetWorkDuration()150     public void testUpdateTargetWorkDuration() {
151         Session s = createSession();
152         assumeNotNull(s);
153         s.updateTargetWorkDuration(100);
154     }
155 
156     @Test
testNativeUpdateTargetWorkDuration()157     public void testNativeUpdateTargetWorkDuration() {
158         final String failureMessage = nativeUpdateTargetWorkDuration();
159         if (!Strings.isNullOrEmpty(failureMessage)) {
160             fail(failureMessage);
161         }
162     }
163 
164     @Test
testUpdateTargetWorkDurationWithNegativeDuration()165     public void testUpdateTargetWorkDurationWithNegativeDuration() {
166         Session s = createSession();
167         assumeNotNull(s);
168         assertThrows(IllegalArgumentException.class, () -> {
169             s.updateTargetWorkDuration(-1);
170         });
171     }
172 
173     @Test
testNativeUpdateTargetWorkDurationWithNegativeDuration()174     public void testNativeUpdateTargetWorkDurationWithNegativeDuration() {
175         final String failureMessage = nativeUpdateTargetWorkDurationWithNegativeDuration();
176         if (!Strings.isNullOrEmpty(failureMessage)) {
177             fail(failureMessage);
178         }
179     }
180 
181     @Test
testReportActualWorkDuration()182     public void testReportActualWorkDuration() {
183         Session s = createSession();
184         assumeNotNull(s);
185         s.updateTargetWorkDuration(100);
186         s.reportActualWorkDuration(1);
187         s.reportActualWorkDuration(100);
188         s.reportActualWorkDuration(1000);
189     }
190 
191     @Test
testNativeReportActualWorkDuration()192     public void testNativeReportActualWorkDuration() {
193         final String failureMessage = nativeReportActualWorkDuration();
194         if (!Strings.isNullOrEmpty(failureMessage)) {
195             fail(failureMessage);
196         }
197     }
198 
199     @Test
testReportActualWorkDurationWithIllegalArgument()200     public void testReportActualWorkDurationWithIllegalArgument() {
201         Session s = createSession();
202         assumeNotNull(s);
203         s.updateTargetWorkDuration(100);
204         assertThrows(IllegalArgumentException.class, () -> {
205             s.reportActualWorkDuration(-1);
206         });
207     }
208 
209     @Test
testNativeReportActualWorkDurationWithIllegalArgument()210     public void testNativeReportActualWorkDurationWithIllegalArgument() {
211         final String failureMessage = nativeReportActualWorkDurationWithIllegalArgument();
212         if (!Strings.isNullOrEmpty(failureMessage)) {
213             fail(failureMessage);
214         }
215     }
216 
217     @Test
218     @ApiTest(apis = {"android.os.PerformanceHintManager.Session#sendHint"})
testSendHint()219     public void testSendHint() {
220         Session s = createSession();
221         assumeNotNull(s);
222         s.sendHint(Session.CPU_LOAD_UP);
223         s.sendHint(Session.CPU_LOAD_RESET);
224         s.sendHint(Session.GPU_LOAD_UP);
225         s.sendHint(Session.GPU_LOAD_DOWN);
226         s.sendHint(Session.GPU_LOAD_RESET);
227     }
228 
229     @Test
230     @ApiTest(apis = {"android.os.PerformanceHintManager.Session#sendHint"})
testSendHintWithNegativeHint()231     public void testSendHintWithNegativeHint() {
232         Session s = createSession();
233         assumeNotNull(s);
234         assertThrows(IllegalArgumentException.class, () -> {
235             s.sendHint(-1);
236         });
237     }
238 
239     @Test
testCloseHintSession()240     public void testCloseHintSession() {
241         Session s = createSession();
242         assumeNotNull(s);
243         s.close();
244     }
245 
246     private static final class SyncRunnable implements Runnable {
247 
248         /** true if run is completed. */
249         private boolean mHadCompleted;
250 
SyncRunnable()251         SyncRunnable() {}
252 
run()253         public void run() {
254             synchronized (this) {
255                 mHadCompleted = true;
256                 notifyAll();
257             }
258         }
259 
waitForComplete()260         public synchronized void waitForComplete() throws InterruptedException {
261             if (!mHadCompleted) {
262                 wait(1000);
263             }
264         }
265     }
266 
267     private static class TestHandlerThread extends HandlerThread {
268         private Runnable mTarget;
269 
TestHandlerThread(Runnable target)270         TestHandlerThread(Runnable target) {
271             super("testSetThreadIdsHandlerThread");
272             mTarget = target;
273         }
274 
275         @Override
onLooperPrepared()276         protected void onLooperPrepared() {
277             super.onLooperPrepared();
278             mTarget.run();
279         }
280     }
281 
282     @Test
283     @ApiTest(apis = {"android.os.PerformanceHintManager.Session#setThreads"})
testSetThreads()284     public void testSetThreads() {
285         Session s = createSession();
286         assumeNotNull(s);
287         int[] oldTids = new int[]{Process.myPid()};
288         assertArrayEquals(oldTids, s.getThreadIds());
289 
290         final SyncRunnable sr = new SyncRunnable();
291         HandlerThread thread = new TestHandlerThread(sr);
292         thread.start();
293         try {
294             sr.waitForComplete();
295         } catch (InterruptedException e) {
296             Log.e(TAG, "Error happens when waiting for handler thread: " + e);
297         }
298         int[] newTids = new int[]{thread.getThreadId()};
299         s.setThreads(newTids);
300         assertArrayEquals(newTids, s.getThreadIds());
301     }
302 
303     @Test
304     @ApiTest(apis = {"android.os.PerformanceHintManager.Session#setThreads"})
testSetThreadsWithEmptyList()305     public void testSetThreadsWithEmptyList() {
306         Session s = createSession();
307         assumeNotNull(s);
308         assertThrows(IllegalArgumentException.class, () -> {
309             s.setThreads(new int[]{});
310         });
311     }
312 
313     @Test
314     @ApiTest(apis = {"android.os.PerformanceHintManager.Session#setThreads"})
testSetThreadsWithInvalidTid()315     public void testSetThreadsWithInvalidTid() {
316         final String failureMessage = nativeTestSetThreadsWithInvalidTid();
317         if (!Strings.isNullOrEmpty(failureMessage)) {
318             fail(failureMessage);
319         }
320     }
321 
322     @Test
323     @ApiTest(apis = {"android.os.PerformanceHintManager.Session#setPreferPowerEfficiency"})
testSetPreferPowerEfficiency()324     public void testSetPreferPowerEfficiency() {
325         Session s = createSession();
326         assumeNotNull(s);
327         s.setPreferPowerEfficiency(false);
328         s.setPreferPowerEfficiency(true);
329         s.setPreferPowerEfficiency(true);
330     }
331 
332     @Test
333     @ApiTest(apis = {"android.os.PerformanceHintManager.Session#setPreferPowerEfficiency"})
testNativeSetPreferPowerEfficiency()334     public void testNativeSetPreferPowerEfficiency() {
335         final String failureMessage = nativeSetPreferPowerEfficiency();
336         if (!Strings.isNullOrEmpty(failureMessage)) {
337             fail(failureMessage);
338         }
339     }
340 
341     @Test
342     @RequiresFlagsEnabled(Flags.FLAG_ADPF_GPU_REPORT_ACTUAL_WORK_DURATION)
343     @ApiTest(apis = {"android.os.PerformanceHintManager.Session#reportActualWorkDuration"})
testReportActualWorkDurationWithWorkDurationClass()344     public void testReportActualWorkDurationWithWorkDurationClass() {
345         Session s = createSession();
346         assumeNotNull(s);
347         s.updateTargetWorkDuration(16);
348         WorkDuration workDuration = new WorkDuration();
349         workDuration.setWorkPeriodStartTimestampNanos(1000);
350         workDuration.setActualTotalDurationNanos(15);
351         workDuration.setActualCpuDurationNanos(11);
352         workDuration.setActualGpuDurationNanos(8);
353         s.reportActualWorkDuration(workDuration);
354     }
355 
356     @Test
357     // TODO(b/304828176): Support NDK API annotation.
358     @ApiTest(apis = {"APerformanceHint_reportActualWorkDuration2"})
testNativeReportActualWorkDuration2()359     public void testNativeReportActualWorkDuration2() {
360         final String resultMessage = nativeTestReportActualWorkDuration2();
361         if (!Strings.isNullOrEmpty(resultMessage)) {
362             fail(resultMessage);
363         }
364     }
365 
366     @Test
367     // TODO(b/304828176): Support NDK API annotation.
368     @ApiTest(apis = {"APerformanceHint_reportActualWorkDuration2"})
testNativeReportActualWorkDuration2WithIllegalArgument()369     public void testNativeReportActualWorkDuration2WithIllegalArgument() {
370         final String resultMessage = nativeTestReportActualWorkDuration2WithIllegalArgument();
371         if (!Strings.isNullOrEmpty(resultMessage)) {
372             fail(resultMessage);
373         }
374     }
375 
376     @Test
377     // TODO(b/304828176): Support NDK API annotation.
378     @ApiTest(apis = {"APerformanceHint_notifyWorkloadIncrease",
379                      "APerformanceHint_notifyWorkloadReset"})
testNativeLoadHints()380     public void testNativeLoadHints() {
381         final String resultMessage = nativeTestLoadHints();
382         if (!Strings.isNullOrEmpty(resultMessage)) {
383             fail(resultMessage);
384         }
385     }
386 
387     @Test
388     // TODO(b/304828176): Support NDK API annotation.
389     @ApiTest(apis = {"APerformanceHint_borrowSessionFromJava"})
testNativeBorrowSessionFromJava()390     public void testNativeBorrowSessionFromJava() {
391         Session session = createSession();
392         assumeNotNull(session);
393         long nativeSession = nativeBorrowSessionFromJava(session);
394         assertNotEquals(0, nativeSession);
395     }
396 
testNativeCreateHintSessionUsingConfig()397     public void testNativeCreateHintSessionUsingConfig() {
398         final String resultMessage = nativeTestCreateHintSessionUsingConfig();
399         if (!Strings.isNullOrEmpty(resultMessage)) {
400             fail(resultMessage);
401         }
402     }
403 
404     @Test
testNativeCreateGraphicsPipelineSessionOverLimit()405     public void testNativeCreateGraphicsPipelineSessionOverLimit() {
406         final String resultMessage = nativeTestCreateGraphicsPipelineSessionOverLimit();
407         if (!Strings.isNullOrEmpty(resultMessage)) {
408             fail(resultMessage);
409         }
410     }
411 
412     @Test
testNativeSetNativeSurfaces()413     public void testNativeSetNativeSurfaces() {
414         makeSurfaceControl();
415 
416         Surface surface = new Surface(mSurfaceControl);
417 
418         final String resultMessage = nativeTestSetNativeSurfaces(mSurfaceControl, surface);
419         if (!Strings.isNullOrEmpty(resultMessage)) {
420             fail(resultMessage);
421         }
422     }
423 
424     @Test
testNativeAutoSessionTiming()425     public void testNativeAutoSessionTiming() {
426         makeSurfaceControl();
427 
428         final String resultMessage = nativeTestAutoSessionTiming(mSurfaceControl);
429         if (!Strings.isNullOrEmpty(resultMessage)) {
430             fail(resultMessage);
431         }
432     }
433 
nativeTestCreateGraphicsPipelineSessionOverLimit()434     private native String nativeTestCreateGraphicsPipelineSessionOverLimit();
nativeTestCreateHintSession()435     private native String nativeTestCreateHintSession();
nativeTestCreateHintSessionUsingConfig()436     private native String nativeTestCreateHintSessionUsingConfig();
nativeTestGetMaxGraphicsPipelineThreadsCount()437     private native String nativeTestGetMaxGraphicsPipelineThreadsCount();
nativeTestGetPreferredUpdateRateNanos()438     private native String nativeTestGetPreferredUpdateRateNanos();
nativeUpdateTargetWorkDuration()439     private native String nativeUpdateTargetWorkDuration();
nativeUpdateTargetWorkDurationWithNegativeDuration()440     private native String nativeUpdateTargetWorkDurationWithNegativeDuration();
nativeReportActualWorkDuration()441     private native String nativeReportActualWorkDuration();
nativeReportActualWorkDurationWithIllegalArgument()442     private native String nativeReportActualWorkDurationWithIllegalArgument();
nativeTestSetThreadsWithInvalidTid()443     private native String nativeTestSetThreadsWithInvalidTid();
nativeSetPreferPowerEfficiency()444     private native String nativeSetPreferPowerEfficiency();
nativeTestReportActualWorkDuration2()445     private native String nativeTestReportActualWorkDuration2();
nativeTestReportActualWorkDuration2WithIllegalArgument()446     private native String nativeTestReportActualWorkDuration2WithIllegalArgument();
nativeTestLoadHints()447     private native String nativeTestLoadHints();
nativeBorrowSessionFromJava(Session session)448     private native long nativeBorrowSessionFromJava(Session session);
nativeTestSetNativeSurfaces( SurfaceControl surfaceControl, Surface surface)449     private native String nativeTestSetNativeSurfaces(
450             SurfaceControl surfaceControl, Surface surface);
nativeTestAutoSessionTiming(SurfaceControl surfaceControl)451     private native String nativeTestAutoSessionTiming(SurfaceControl surfaceControl);
452 }
453