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.traces.component.ComponentNameMatcher 29 import android.tools.traces.io.IResultData 30 import android.tools.utils.TestComponents 31 import android.tools.utils.assertFail 32 import android.tools.utils.assertThatErrorContainsDebugInfo 33 import android.tools.utils.assertThrows 34 import android.tools.utils.getLayerTraceReaderFromAsset 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