• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2023 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.tools.flicker.subject.surfaceflinger
18 
19 import android.graphics.Region
20 import android.tools.Cache
21 import android.tools.CleanFlickerEnvironmentRuleWithDataStore
22 import android.tools.ScenarioBuilder
23 import android.tools.Timestamps
24 import android.tools.flicker.legacy.LegacyFlickerTest
25 import android.tools.flicker.subject.layers.LayersTraceSubject
26 import android.tools.flicker.subject.region.RegionSubject
27 import android.tools.io.Reader
28 import android.tools.testutils.TestComponents
29 import android.tools.testutils.assertFail
30 import android.tools.testutils.assertThatErrorContainsDebugInfo
31 import android.tools.testutils.assertThrows
32 import android.tools.testutils.getLayerTraceReaderFromAsset
33 import android.tools.traces.component.ComponentNameMatcher
34 import android.tools.traces.io.IResultData
35 import androidx.test.filters.FlakyTest
36 import com.google.common.truth.Truth
37 import org.junit.Before
38 import org.junit.ClassRule
39 import org.junit.FixMethodOrder
40 import org.junit.Test
41 import org.junit.runners.MethodSorters
42 import org.mockito.Mockito
43 
44 /**
45  * Contains [LayersTraceSubject] tests. To run this test: `atest
46  * FlickerLibTest:LayersTraceSubjectTest`
47  */
48 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
49 class LayersTraceSubjectTest {
50     @Before
51     fun before() {
52         Cache.clear()
53     }
54 
55     @Test
56     fun exceptionContainsDebugInfo() {
57         val reader = getLayerTraceReaderFromAsset("layers_trace_launch_split_screen.perfetto-trace")
58         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
59         val error = assertThrows<AssertionError> { LayersTraceSubject(trace, reader).isEmpty() }
60         assertThatErrorContainsDebugInfo(error)
61     }
62 
63     @Test
64     fun testCanDetectEmptyRegionFromLayerTrace() {
65         val reader = getLayerTraceReaderFromAsset("layers_trace_emptyregion.perfetto-trace")
66         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
67         assertFail("SkRegion((0,0,1440,1440)) should cover at least SkRegion((0,0,1440,2880))") {
68             LayersTraceSubject(trace, reader)
69                 .visibleRegion()
70                 .coversAtLeast(DISPLAY_REGION)
71                 .forAllEntries()
72             error("Assertion should not have passed")
73         }
74     }
75 
76     @Test
77     fun testCanInspectBeginning() {
78         val reader = getLayerTraceReaderFromAsset("layers_trace_launch_split_screen.perfetto-trace")
79         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
80         LayersTraceSubject(trace, reader)
81             .first()
82             .isVisible(ComponentNameMatcher.NAV_BAR)
83             .notContains(TestComponents.DOCKER_STACK_DIVIDER)
84             .isVisible(TestComponents.LAUNCHER)
85     }
86 
87     @Test
88     fun testCanInspectEnd() {
89         val reader = getLayerTraceReaderFromAsset("layers_trace_launch_split_screen.perfetto-trace")
90         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
91         LayersTraceSubject(trace, reader)
92             .last()
93             .isVisible(ComponentNameMatcher.NAV_BAR)
94             .isVisible(TestComponents.DOCKER_STACK_DIVIDER)
95     }
96 
97     @Test
98     fun testAssertionsOnRange() {
99         val reader = getLayerTraceReaderFromAsset("layers_trace_launch_split_screen.perfetto-trace")
100         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
101 
102         LayersTraceSubject(trace, reader)
103             .isVisible(ComponentNameMatcher.NAV_BAR)
104             .isInvisible(TestComponents.DOCKER_STACK_DIVIDER)
105             .forSystemUpTimeRange(90480846872160L, 90480994138424L)
106 
107         LayersTraceSubject(trace, reader)
108             .isVisible(ComponentNameMatcher.NAV_BAR)
109             .isVisible(TestComponents.DOCKER_STACK_DIVIDER)
110             .forSystemUpTimeRange(90491795074136L, 90493757372977L)
111     }
112 
113     @Test
114     fun testCanDetectChangingAssertions() {
115         val reader = getLayerTraceReaderFromAsset("layers_trace_launch_split_screen.perfetto-trace")
116         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
117         LayersTraceSubject(trace, reader)
118             .isVisible(ComponentNameMatcher.NAV_BAR)
119             .notContains(TestComponents.DOCKER_STACK_DIVIDER)
120             .then()
121             .isVisible(ComponentNameMatcher.NAV_BAR)
122             .isInvisible(TestComponents.DOCKER_STACK_DIVIDER)
123             .then()
124             .isVisible(ComponentNameMatcher.NAV_BAR)
125             .isVisible(TestComponents.DOCKER_STACK_DIVIDER)
126             .forAllEntries()
127     }
128 
129     @FlakyTest
130     @Test
131     fun testCanDetectIncorrectVisibilityFromLayerTrace() {
132         val reader =
133             getLayerTraceReaderFromAsset("layers_trace_invalid_layer_visibility.perfetto-trace")
134         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
135         val error =
136             assertThrows<AssertionError> {
137                 LayersTraceSubject(trace, reader)
138                     .isVisible(TestComponents.SIMPLE_APP)
139                     .then()
140                     .isInvisible(TestComponents.SIMPLE_APP)
141                     .forAllEntries()
142             }
143 
144         Truth.assertThat(error)
145             .hasMessageThat()
146             .contains("layers_trace_invalid_layer_visibility.perfetto-trace")
147         Truth.assertThat(error).hasMessageThat().contains("2d22h13m14s303ms")
148         Truth.assertThat(error).hasMessageThat().contains("!isVisible")
149         Truth.assertThat(error)
150             .hasMessageThat()
151             .contains(
152                 "com.android.server.wm.flicker.testapp/" +
153                     "com.android.server.wm.flicker.testapp.SimpleActivity#0 is visible"
154             )
155     }
156 
157     @Test
158     fun testCanDetectInvalidVisibleLayerForMoreThanOneConsecutiveEntry() {
159         val reader =
160             getLayerTraceReaderFromAsset("layers_trace_invalid_visible_layers.perfetto-trace")
161         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
162         val error =
163             assertThrows<AssertionError> {
164                 LayersTraceSubject(trace, reader)
165                     .visibleLayersShownMoreThanOneConsecutiveEntry()
166                     .forAllEntries()
167                 error("Assertion should not have passed")
168             }
169 
170         Truth.assertThat(error).hasMessageThat().contains("2d18h35m56s397ms")
171         Truth.assertThat(error).hasMessageThat().contains("StatusBar#0")
172         Truth.assertThat(error).hasMessageThat().contains("is not visible for 2 entries")
173     }
174 
175     private fun testCanDetectVisibleLayersMoreThanOneConsecutiveEntry(reader: Reader) {
176         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
177         LayersTraceSubject(trace, reader)
178             .visibleLayersShownMoreThanOneConsecutiveEntry()
179             .forAllEntries()
180     }
181 
182     @Test
183     fun testCanDetectVisibleLayersMoreThanOneConsecutiveEntry() {
184         testCanDetectVisibleLayersMoreThanOneConsecutiveEntry(
185             getLayerTraceReaderFromAsset("layers_trace_snapshot_visible.perfetto-trace")
186         )
187     }
188 
189     @Test
190     fun testCanIgnoreLayerEqualNameInVisibleLayersMoreThanOneConsecutiveEntry() {
191         val reader =
192             getLayerTraceReaderFromAsset("layers_trace_invalid_visible_layers.perfetto-trace")
193         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
194         LayersTraceSubject(trace, reader)
195             .visibleLayersShownMoreThanOneConsecutiveEntry(listOf(ComponentNameMatcher.STATUS_BAR))
196             .forAllEntries()
197     }
198 
199     @Test
200     fun testCanIgnoreLayerShorterNameInVisibleLayersMoreThanOneConsecutiveEntry() {
201         val reader = getLayerTraceReaderFromAsset("one_visible_layer_launcher_trace.perfetto-trace")
202         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
203         val launcherComponent =
204             ComponentNameMatcher(
205                 "com.google.android.apps.nexuslauncher",
206                 "com.google.android.apps.nexuslauncher.NexusLauncherActivity#1",
207             )
208         LayersTraceSubject(trace, reader)
209             .visibleLayersShownMoreThanOneConsecutiveEntry(listOf(launcherComponent))
210             .forAllEntries()
211     }
212 
213     private fun detectRootLayer(fileName: String) {
214         val reader = getLayerTraceReaderFromAsset(fileName)
215         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
216         for (entry in trace.entries) {
217             val rootLayers = entry.children
218             Truth.assertWithMessage("Does not have any root layer")
219                 .that(rootLayers.size)
220                 .isGreaterThan(0)
221             val firstParentId = rootLayers.first().parentId
222             Truth.assertWithMessage("Has multiple root layers")
223                 .that(rootLayers.all { it.parentId == firstParentId })
224                 .isTrue()
225         }
226     }
227 
228     @Test
229     fun testCanDetectRootLayer() {
230         detectRootLayer("layers_trace_root.perfetto-trace")
231     }
232 
233     @Test
234     fun testCanDetectRootLayerAOSP() {
235         detectRootLayer("layers_trace_root_aosp.perfetto-trace")
236     }
237 
238     @Test
239     fun canTestLayerOccludedBySplashScreenLayerIsNotVisible() {
240         val reader = getLayerTraceReaderFromAsset("layers_trace_occluded.perfetto-trace")
241         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
242         val entry =
243             LayersTraceSubject(trace, reader)
244                 .getEntryBySystemUpTime(1700382131522L, byElapsedTimestamp = true)
245         entry.isInvisible(TestComponents.SIMPLE_APP)
246         entry.isVisible(ComponentNameMatcher.SPLASH_SCREEN)
247     }
248 
249     @Test
250     fun testCanDetectLayerExpanding() {
251         val reader = getLayerTraceReaderFromAsset("layers_trace_openchrome.perfetto-trace")
252         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
253         val animation =
254             LayersTraceSubject(trace, reader).layers("animation-leash of app_transition#0")
255         // Obtain the area of each layer and checks if the next area is
256         // greater or equal to the previous one
257         val areas =
258             animation.map {
259                 val region = it.layer.visibleRegion ?: Region()
260                 val bounds = region.bounds
261                 val area = bounds.width() * bounds.height()
262                 area
263             }
264         val expanding = areas.zipWithNext { currentArea, nextArea -> nextArea >= currentArea }
265 
266         Truth.assertWithMessage("Animation leash should be expanding")
267             .that(expanding.all { it })
268             .isTrue()
269     }
270 
271     @Test
272     fun checkVisibleRegionAppMinusPipLayer() {
273         val reader = getLayerTraceReaderFromAsset("layers_trace_pip_wmshell.perfetto-trace")
274         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
275         val subject = LayersTraceSubject(trace, reader).last()
276 
277         try {
278             subject.visibleRegion(TestComponents.FIXED_APP).coversExactly(DISPLAY_REGION_ROTATED)
279             error(
280                 "Layer is partially covered by a Pip layer and should not cover the device screen"
281             )
282         } catch (e: AssertionError) {
283             val pipRegion = subject.visibleRegion(TestComponents.PIP_APP).region
284             val expectedWithoutPip = DISPLAY_REGION_ROTATED.minus(pipRegion)
285             subject.visibleRegion(TestComponents.FIXED_APP).coversExactly(expectedWithoutPip)
286         }
287     }
288 
289     @Test
290     fun checkVisibleRegionAppPlusPipLayer() {
291         val reader = getLayerTraceReaderFromAsset("layers_trace_pip_wmshell.perfetto-trace")
292         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
293         val subject = LayersTraceSubject(trace, reader).last()
294         val pipRegion = subject.visibleRegion(TestComponents.PIP_APP).region
295         subject
296             .visibleRegion(TestComponents.FIXED_APP)
297             .plus(pipRegion)
298             .coversExactly(DISPLAY_REGION_ROTATED)
299     }
300 
301     @Test
302     fun checkCanDetectSplashScreen() {
303         val reader = getLayerTraceReaderFromAsset("layers_trace_splashscreen.perfetto-trace")
304         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
305         LayersTraceSubject(trace, reader)
306             .isVisible(TestComponents.LAUNCHER)
307             .then()
308             .isSplashScreenVisibleFor(TestComponents.SIMPLE_APP, isOptional = false)
309             .then()
310             .isVisible(TestComponents.SIMPLE_APP)
311             .forAllEntries()
312 
313         assertFail("SimpleActivity# should be visible") {
314             LayersTraceSubject(trace, reader)
315                 .isVisible(TestComponents.LAUNCHER)
316                 .then()
317                 .isVisible(TestComponents.SIMPLE_APP)
318                 .forAllEntries()
319         }
320     }
321 
322     @Test
323     fun checkCanDetectMissingSplashScreen() {
324         val reader = getLayerTraceReaderFromAsset("layers_trace_splashscreen.perfetto-trace")
325         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
326 
327         // No splashscreen because no matching activity record
328         assertFail("SimpleActivity# should exist") {
329             LayersTraceSubject(trace, reader)
330                 .first()
331                 .isSplashScreenVisibleFor(TestComponents.SIMPLE_APP)
332         }
333     }
334 
335     @Test
336     fun snapshotStartingWindowLayerCoversExactlyApp() {
337         val reader =
338             getLayerTraceReaderFromAsset(
339                 "layers_trace_snapshotStartingWindowLayerCoversExactlyApp.perfetto-trace",
340                 from = Timestamps.from(systemUptimeNanos = 1688243428961872440),
341                 to = Timestamps.from(systemUptimeNanos = 1688243432147782644),
342             )
343         val component =
344             ComponentNameMatcher(FLICKER_APP_PACKAGE, "$FLICKER_APP_PACKAGE.ImeActivity")
345         val builder = ScenarioBuilder()
346         val flicker = LegacyFlickerTest(builder, { _ -> reader })
347         val scenario = flicker.initialize("test")
348         val result = Mockito.mock(IResultData::class.java)
349         android.tools.flicker.datastore.DataStore.addResult(scenario, result)
350         flicker.assertLayers {
351             invoke("snapshotStartingWindowLayerCoversExactlyOnApp") {
352                 val snapshotLayers =
353                     it.subjects.filter { subject ->
354                         ComponentNameMatcher.SNAPSHOT.layerMatchesAnyOf(subject.layer) &&
355                             subject.isVisible
356                     }
357                 val visibleAreas =
358                     snapshotLayers.mapNotNull { snapshotLayer -> snapshotLayer.layer.visibleRegion }
359                 val snapshotRegion = RegionSubject(visibleAreas, timestamp)
360                 // Verify the size of snapshotRegion covers appVisibleRegion exactly in animation.
361                 if (!snapshotRegion.region.isEmpty) {
362                     val appVisibleRegion = it.visibleRegion(component)
363                     snapshotRegion.coversExactly(appVisibleRegion.region)
364                 }
365             }
366         }
367     }
368 
369     companion object {
370         private const val LABEL = "ImeActivity"
371         private const val FLICKER_APP_PACKAGE = "com.android.server.wm.flicker.testapp"
372 
373         private val DISPLAY_REGION = Region(0, 0, 1440, 2880)
374         private val DISPLAY_REGION_ROTATED = Region(0, 0, 2160, 1080)
375 
376         @ClassRule @JvmField val ENV_CLEANUP = CleanFlickerEnvironmentRuleWithDataStore()
377 
378         private fun Region.minus(other: Region): Region {
379             val thisRegion = Region(this)
380             thisRegion.op(other, Region.Op.XOR)
381             return thisRegion
382         }
383     }
384 }
385