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