xref: /aosp_15_r20/platform_testing/libraries/flicker/README.md (revision dd0948b35e70be4c0246aabd6c72554a5eb8b22a)
1*dd0948b3SAndroid Build Coastguard Worker# Flicker Test Library
2*dd0948b3SAndroid Build Coastguard Worker
3*dd0948b3SAndroid Build Coastguard Worker## Motivation
4*dd0948b3SAndroid Build Coastguard WorkerDetect *flicker* — any discontinuous, or unpredictable behavior seen during UI transitions that is not due to performance.
5*dd0948b3SAndroid Build Coastguard WorkerThis is often the result of a logic error in the code and difficult to identify because the issue is transient and at times difficult to reproduce.
6*dd0948b3SAndroid Build Coastguard WorkerThis library helps create integration tests between `SurfaceFlinger`, `WindowManager` and `SystemUI` to identify flicker.
7*dd0948b3SAndroid Build Coastguard Worker
8*dd0948b3SAndroid Build Coastguard WorkerExamples of flickers are:
9*dd0948b3SAndroid Build Coastguard Worker* Elements drawn in the wrong location (e.g., not rotating correctly)
10*dd0948b3SAndroid Build Coastguard Worker* Empty areas on the screen (e.g., not all areas of the screen covered during rotation)
11*dd0948b3SAndroid Build Coastguard Worker* System elements not appearing (e.g., nav and status bar or split screen divider)
12*dd0948b3SAndroid Build Coastguard Worker* Elements (dis)appearing at the wrong time (e.g., an element becomes invisible before being completely occluded)
13*dd0948b3SAndroid Build Coastguard Worker
14*dd0948b3SAndroid Build Coastguard Worker## Usage and Capabilities
15*dd0948b3SAndroid Build Coastguard Worker
16*dd0948b3SAndroid Build Coastguard WorkerThe library builds and runs UI transitions, captures Winscope [traces](https://source.android.com/devices/graphics/tracing-win-transitions) and exposes common assertions that can be tested against each trace.
17*dd0948b3SAndroid Build Coastguard Worker
18*dd0948b3SAndroid Build Coastguard Worker## Building a transition
19*dd0948b3SAndroid Build Coastguard Worker
20*dd0948b3SAndroid Build Coastguard WorkerStart by defining common or error prone transitions using `TransitionRunner`.
21*dd0948b3SAndroid Build Coastguard Worker```java
22*dd0948b3SAndroid Build Coastguard Worker// Example: Build a transition that cold launches an app from launcher
23*dd0948b3SAndroid Build Coastguard WorkerTransitionRunner transition = new TransitionBuilder()
24*dd0948b3SAndroid Build Coastguard Worker                // Specify a tag to identify the transition (optional)
25*dd0948b3SAndroid Build Coastguard Worker                .withTag("OpenAppCold_" + testApp.getLauncherName())
26*dd0948b3SAndroid Build Coastguard Worker
27*dd0948b3SAndroid Build Coastguard Worker                // Specify preconditions to setup the device
28*dd0948b3SAndroid Build Coastguard Worker                // Wake up device and go to home screen
29*dd0948b3SAndroid Build Coastguard Worker                .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
30*dd0948b3SAndroid Build Coastguard Worker
31*dd0948b3SAndroid Build Coastguard Worker                // Setup transition under test
32*dd0948b3SAndroid Build Coastguard Worker                // Press the home button and close the app to test a cold start
33*dd0948b3SAndroid Build Coastguard Worker                .runBefore(device::pressHome)
34*dd0948b3SAndroid Build Coastguard Worker                .runBefore(testApp::exit)
35*dd0948b3SAndroid Build Coastguard Worker
36*dd0948b3SAndroid Build Coastguard Worker                // Run the transition under test
37*dd0948b3SAndroid Build Coastguard Worker                // Open the app and wait for UI to be idle
38*dd0948b3SAndroid Build Coastguard Worker                // This is the part of the transition that will be tested.
39*dd0948b3SAndroid Build Coastguard Worker                .run(testApp::open)
40*dd0948b3SAndroid Build Coastguard Worker                .run(device::waitForIdle)
41*dd0948b3SAndroid Build Coastguard Worker
42*dd0948b3SAndroid Build Coastguard Worker                // Perform any tear downs
43*dd0948b3SAndroid Build Coastguard Worker                // Close the app
44*dd0948b3SAndroid Build Coastguard Worker                .runAfterAll(testApp::exit)
45*dd0948b3SAndroid Build Coastguard Worker
46*dd0948b3SAndroid Build Coastguard Worker                // Number of times to repeat the transition to catch any flaky issues
47*dd0948b3SAndroid Build Coastguard Worker                .repeat(5);
48*dd0948b3SAndroid Build Coastguard Worker```
49*dd0948b3SAndroid Build Coastguard Worker
50*dd0948b3SAndroid Build Coastguard WorkerRun the transition to get a list of `TransitionResult` for each time the transition is repeated.
51*dd0948b3SAndroid Build Coastguard Worker```java
52*dd0948b3SAndroid Build Coastguard Worker    List<TransitionResult> results = transition.run();
53*dd0948b3SAndroid Build Coastguard Worker```
54*dd0948b3SAndroid Build Coastguard Worker`TransitionResult` contains paths to test artifacts such as Winscope traces and screen recordings.
55*dd0948b3SAndroid Build Coastguard Worker
56*dd0948b3SAndroid Build Coastguard Worker### Checking Assertions
57*dd0948b3SAndroid Build Coastguard WorkerEach `TransitionResult` can be tested using an extension of the Google Truth library, `LayersTraceSubject` and `WmTraceSubject`.
58*dd0948b3SAndroid Build Coastguard WorkerThey try to balance test principles set out by Google Truth (not supporting nested assertions, keeping assertions simple) with providing support for common assertion use cases.
59*dd0948b3SAndroid Build Coastguard Worker
60*dd0948b3SAndroid Build Coastguard WorkerEach trace can be represented as a ordered collection of trace entries, with an associated timestamp.
61*dd0948b3SAndroid Build Coastguard WorkerEach trace entry has common assertion checks.
62*dd0948b3SAndroid Build Coastguard WorkerThe trace subjects expose methods to filter the range of entries and test for changing assertions.
63*dd0948b3SAndroid Build Coastguard Worker
64*dd0948b3SAndroid Build Coastguard Worker```java
65*dd0948b3SAndroid Build Coastguard Worker    TransitionResult result = results.get(0);
66*dd0948b3SAndroid Build Coastguard Worker    Rect displayBounds = getDisplayBounds();
67*dd0948b3SAndroid Build Coastguard Worker
68*dd0948b3SAndroid Build Coastguard Worker    // check all trace entries
69*dd0948b3SAndroid Build Coastguard Worker    assertThat(result).coversRegion(displayBounds).forAllEntries();
70*dd0948b3SAndroid Build Coastguard Worker
71*dd0948b3SAndroid Build Coastguard Worker    // check a range of entries
72*dd0948b3SAndroid Build Coastguard Worker    assertThat(result).coversRegion(displayBounds).forRange(startTime, endTime);
73*dd0948b3SAndroid Build Coastguard Worker
74*dd0948b3SAndroid Build Coastguard Worker    // check first entry
75*dd0948b3SAndroid Build Coastguard Worker    assertThat(result).coversRegion(displayBounds).inTheBeginning();
76*dd0948b3SAndroid Build Coastguard Worker
77*dd0948b3SAndroid Build Coastguard Worker    // check last entry
78*dd0948b3SAndroid Build Coastguard Worker    assertThat(result).coversRegion(displayBounds).atTheEnd();
79*dd0948b3SAndroid Build Coastguard Worker
80*dd0948b3SAndroid Build Coastguard Worker    // check a change in assertions, e.g. wallpaper window is visible,
81*dd0948b3SAndroid Build Coastguard Worker    // then wallpaper window becomes and stays invisible
82*dd0948b3SAndroid Build Coastguard Worker    assertThat(result)
83*dd0948b3SAndroid Build Coastguard Worker                .showsBelowAppWindow("wallpaper")
84*dd0948b3SAndroid Build Coastguard Worker                .then()
85*dd0948b3SAndroid Build Coastguard Worker                .hidesBelowAppWindow("wallpaper")
86*dd0948b3SAndroid Build Coastguard Worker                .forAllEntries();
87*dd0948b3SAndroid Build Coastguard Worker```
88*dd0948b3SAndroid Build Coastguard Worker
89*dd0948b3SAndroid Build Coastguard WorkerAll assertions return `Result` which contains a `success` flag, `assertionName` string identifier, and `reason` string to provide actionable details to the user.
90*dd0948b3SAndroid Build Coastguard WorkerThe `reason` string is build along the way with all the details as to why the assertions failed and any hints which might help the user determine the root cause.
91*dd0948b3SAndroid Build Coastguard WorkerFailed assertion message will also contain a path to the trace that was tested.
92*dd0948b3SAndroid Build Coastguard WorkerExample of a failed test:
93*dd0948b3SAndroid Build Coastguard Worker
94*dd0948b3SAndroid Build Coastguard Worker```
95*dd0948b3SAndroid Build Coastguard Worker    java.lang.AssertionError: Not true that <com.android.server.wm.traces.common.LayersTrace@65da4cc>
96*dd0948b3SAndroid Build Coastguard Worker    Layers Trace can be found in: /layers_trace_emptyregion.pb
97*dd0948b3SAndroid Build Coastguard Worker    Timestamp: 2308008331271
98*dd0948b3SAndroid Build Coastguard Worker    Assertion: coversRegion
99*dd0948b3SAndroid Build Coastguard Worker    Reason:   Region to test: Rect(0, 0 - 1440, 2880)
100*dd0948b3SAndroid Build Coastguard Worker    first empty point: 0, 99
101*dd0948b3SAndroid Build Coastguard Worker    visible regions:
102*dd0948b3SAndroid Build Coastguard Worker    StatusBar#0Rect(0, 0 - 1440, 98)
103*dd0948b3SAndroid Build Coastguard Worker    NavigationBar#0Rect(0, 2712 - 1440, 2880)
104*dd0948b3SAndroid Build Coastguard Worker    ScreenDecorOverlay#0Rect(0, 0 - 1440, 91)
105*dd0948b3SAndroid Build Coastguard Worker    ...
106*dd0948b3SAndroid Build Coastguard Worker        at com.google.common.truth.FailureStrategy.fail(FailureStrategy.java:24)
107*dd0948b3SAndroid Build Coastguard Worker        ...
108*dd0948b3SAndroid Build Coastguard Worker```
109*dd0948b3SAndroid Build Coastguard Worker
110*dd0948b3SAndroid Build Coastguard Worker---
111*dd0948b3SAndroid Build Coastguard Worker
112*dd0948b3SAndroid Build Coastguard Worker## Running Tests
113*dd0948b3SAndroid Build Coastguard Worker
114*dd0948b3SAndroid Build Coastguard WorkerThe tests can be run as any other Android JUnit tests. `frameworks/base/tests/FlickerTests` uses the library to test common UI transitions. Run `atest FlickerTests` to execute these tests.
115*dd0948b3SAndroid Build Coastguard Worker
116*dd0948b3SAndroid Build Coastguard Worker---
117*dd0948b3SAndroid Build Coastguard Worker
118*dd0948b3SAndroid Build Coastguard Worker## Other Topics
119*dd0948b3SAndroid Build Coastguard Worker### Monitors
120*dd0948b3SAndroid Build Coastguard WorkerMonitors capture test artifacts for each transition run. They are started before each iteration of the test transition (after the `runBefore` calls) and stopped after the transition is completed. Each iteration will produce a new test artifact. The following monitors are available:
121*dd0948b3SAndroid Build Coastguard Worker
122*dd0948b3SAndroid Build Coastguard Worker#### LayersTraceMonitor
123*dd0948b3SAndroid Build Coastguard WorkerCaptures Layers trace. This monitor is started by default. Build a transition with `skipLayersTrace()` to disable this monitor.
124*dd0948b3SAndroid Build Coastguard Worker#### WindowManagerTraceMonitor
125*dd0948b3SAndroid Build Coastguard WorkerCaptures Window Manager trace. This monitor is started by default. Build a transition with `skipWindowManagerTrace()` to disable this monitor.
126*dd0948b3SAndroid Build Coastguard Worker#### ScreenRecorder
127*dd0948b3SAndroid Build Coastguard WorkerCaptures screen to a video file. This monitor is disabled by default. Build a transition with `recordEachRun()` to capture each transition or build with `recordAllRuns()` to capture every transition including setup and teardown.
128*dd0948b3SAndroid Build Coastguard Worker
129*dd0948b3SAndroid Build Coastguard Worker---
130*dd0948b3SAndroid Build Coastguard Worker
131*dd0948b3SAndroid Build Coastguard Worker### Extending Assertions
132*dd0948b3SAndroid Build Coastguard Worker
133*dd0948b3SAndroid Build Coastguard WorkerTo add a new assertion, add a function to one of the trace entry classes, `LayersTrace.Entry` or `WindowManagerTrace.Entry`.
134*dd0948b3SAndroid Build Coastguard Worker
135*dd0948b3SAndroid Build Coastguard Worker```java
136*dd0948b3SAndroid Build Coastguard Worker    // Example adds an assertion to the check if layer is hidden by parent.
137*dd0948b3SAndroid Build Coastguard Worker    Result isHiddenByParent(String layerName) {
138*dd0948b3SAndroid Build Coastguard Worker        // Result should contain a details if assertion fails for any reason
139*dd0948b3SAndroid Build Coastguard Worker        // such as if layer is not found or layer is not hidden by parent
140*dd0948b3SAndroid Build Coastguard Worker        // or layer has no parent.
141*dd0948b3SAndroid Build Coastguard Worker        // ...
142*dd0948b3SAndroid Build Coastguard Worker    }
143*dd0948b3SAndroid Build Coastguard Worker```
144*dd0948b3SAndroid Build Coastguard WorkerThen add a function to the trace subject `LayersTraceSubject` or `WmTraceSubject` which will add the assertion for testing. When the assertion is evaluated, the trace will first be filtered then the assertion will be applied to the remaining entries.
145*dd0948b3SAndroid Build Coastguard Worker
146*dd0948b3SAndroid Build Coastguard Worker```java
147*dd0948b3SAndroid Build Coastguard Worker    public LayersTraceSubject isHiddenByParent(String layerName) {
148*dd0948b3SAndroid Build Coastguard Worker        mChecker.add(entry -> entry.isHiddenByParent(layerName),
149*dd0948b3SAndroid Build Coastguard Worker                "isHiddenByParent(" + layerName + ")");
150*dd0948b3SAndroid Build Coastguard Worker        return this;
151*dd0948b3SAndroid Build Coastguard Worker    }
152*dd0948b3SAndroid Build Coastguard Worker```
153*dd0948b3SAndroid Build Coastguard Worker
154*dd0948b3SAndroid Build Coastguard WorkerTo use the new assertion:
155*dd0948b3SAndroid Build Coastguard Worker```java
156*dd0948b3SAndroid Build Coastguard Worker    // Check if "Chrome" layer is hidden by parent in the first trace entry.
157*dd0948b3SAndroid Build Coastguard Worker    assertThat(result).isHiddenByParent("Chrome").inTheBeginning();
158*dd0948b3SAndroid Build Coastguard Worker```
159