Add perfetto logs to track time spent on part of flicker
Previously we used logcat, but perfetto makes it easier to visualize this data
Bug: 243646243
Test: atest FlickerTests and check the generated perfetto file
Change-Id: I3c79e4e0a80200232bc3eee9b9bf0668f1c16165
diff --git a/libraries/flicker/src/com/android/server/wm/flicker/FlickerTest.kt b/libraries/flicker/src/com/android/server/wm/flicker/FlickerTest.kt
index 91dd7e9..9a60069 100644
--- a/libraries/flicker/src/com/android/server/wm/flicker/FlickerTest.kt
+++ b/libraries/flicker/src/com/android/server/wm/flicker/FlickerTest.kt
@@ -30,6 +30,7 @@
import com.android.server.wm.flicker.traces.windowmanager.WindowManagerStateSubject
import com.android.server.wm.flicker.traces.windowmanager.WindowManagerTraceSubject
import com.android.server.wm.traces.common.IComponentMatcher
+import com.android.server.wm.traces.parser.withPerfettoTrace
/** Specification of a flicker test for JUnit ParameterizedRunner class */
data class FlickerTest(
@@ -60,9 +61,11 @@
* @param assertion Assertion predicate
*/
fun assertWmStart(assertion: WindowManagerStateSubject.() -> Unit) {
- val assertionData =
- wmAssertionFactory.createStartStateAssertion(assertion as FlickerSubject.() -> Unit)
- doRunAssertion(assertionData)
+ withPerfettoTrace("assertWmStart") {
+ val assertionData =
+ wmAssertionFactory.createStartStateAssertion(assertion as FlickerSubject.() -> Unit)
+ doRunAssertion(assertionData)
+ }
}
/**
@@ -71,10 +74,14 @@
* @param assertion Assertion predicate
*/
fun assertWmEnd(assertion: WindowManagerStateSubject.() -> Unit) {
- val wrappedAssertion: (WindowManagerStateSubject) -> Unit = { assertion(it) }
- val assertionData =
- wmAssertionFactory.createEndStateAssertion(wrappedAssertion as (FlickerSubject) -> Unit)
- doRunAssertion(assertionData)
+ withPerfettoTrace("assertWmEnd") {
+ val wrappedAssertion: (WindowManagerStateSubject) -> Unit = { assertion(it) }
+ val assertionData =
+ wmAssertionFactory.createEndStateAssertion(
+ wrappedAssertion as (FlickerSubject) -> Unit
+ )
+ doRunAssertion(assertionData)
+ }
}
/**
@@ -83,11 +90,13 @@
* @param assertion Assertion predicate
*/
fun assertWm(assertion: WindowManagerTraceSubject.() -> Unit) {
- val assertionData =
- wmAssertionFactory.createTraceAssertion(
- assertion as (FlickerTraceSubject<FlickerSubject>) -> Unit
- )
- doRunAssertion(assertionData)
+ withPerfettoTrace("assertWm") {
+ val assertionData =
+ wmAssertionFactory.createTraceAssertion(
+ assertion as (FlickerTraceSubject<FlickerSubject>) -> Unit
+ )
+ doRunAssertion(assertionData)
+ }
}
/**
@@ -96,9 +105,11 @@
* @param assertion Assertion predicate
*/
fun assertWmTag(tag: String, assertion: WindowManagerStateSubject.() -> Unit) {
- val assertionData =
- wmAssertionFactory.createTagAssertion(tag, assertion as FlickerSubject.() -> Unit)
- doRunAssertion(assertionData)
+ withPerfettoTrace("assertWmTag") {
+ val assertionData =
+ wmAssertionFactory.createTagAssertion(tag, assertion as FlickerSubject.() -> Unit)
+ doRunAssertion(assertionData)
+ }
}
/**
@@ -111,8 +122,10 @@
componentMatcher: IComponentMatcher,
assertion: RegionTraceSubject.() -> Unit
) {
- val assertionData = buildWmVisibleRegionAssertion(componentMatcher, assertion)
- doRunAssertion(assertionData)
+ withPerfettoTrace("assertWmVisibleRegion") {
+ val assertionData = buildWmVisibleRegionAssertion(componentMatcher, assertion)
+ doRunAssertion(assertionData)
+ }
}
/**
@@ -121,9 +134,13 @@
* @param assertion Assertion predicate
*/
fun assertLayersStart(assertion: LayerTraceEntrySubject.() -> Unit) {
- val assertionData =
- layersAssertionFactory.createStartStateAssertion(assertion as FlickerSubject.() -> Unit)
- doRunAssertion(assertionData)
+ withPerfettoTrace("assertLayersStart") {
+ val assertionData =
+ layersAssertionFactory.createStartStateAssertion(
+ assertion as FlickerSubject.() -> Unit
+ )
+ doRunAssertion(assertionData)
+ }
}
/**
@@ -132,9 +149,13 @@
* @param assertion Assertion predicate
*/
fun assertLayersEnd(assertion: LayerTraceEntrySubject.() -> Unit) {
- val assertionData =
- layersAssertionFactory.createEndStateAssertion(assertion as FlickerSubject.() -> Unit)
- doRunAssertion(assertionData)
+ withPerfettoTrace("assertLayersEnd") {
+ val assertionData =
+ layersAssertionFactory.createEndStateAssertion(
+ assertion as FlickerSubject.() -> Unit
+ )
+ doRunAssertion(assertionData)
+ }
}
/**
@@ -143,11 +164,13 @@
* @param assertion Assertion predicate
*/
fun assertLayers(assertion: LayersTraceSubject.() -> Unit) {
- val assertionData =
- layersAssertionFactory.createTraceAssertion(
- assertion as (FlickerTraceSubject<FlickerSubject>) -> Unit
- )
- doRunAssertion(assertionData)
+ withPerfettoTrace("assertLayers") {
+ val assertionData =
+ layersAssertionFactory.createTraceAssertion(
+ assertion as (FlickerTraceSubject<FlickerSubject>) -> Unit
+ )
+ doRunAssertion(assertionData)
+ }
}
/**
@@ -156,9 +179,14 @@
* @param assertion Assertion predicate
*/
fun assertLayersTag(tag: String, assertion: LayerTraceEntrySubject.() -> Unit) {
- val assertionData =
- layersAssertionFactory.createTagAssertion(tag, assertion as FlickerSubject.() -> Unit)
- return doRunAssertion(assertionData)
+ withPerfettoTrace("assertLayersTag") {
+ val assertionData =
+ layersAssertionFactory.createTagAssertion(
+ tag,
+ assertion as FlickerSubject.() -> Unit
+ )
+ doRunAssertion(assertionData)
+ }
}
/**
@@ -177,13 +205,15 @@
useCompositionEngineRegionOnly: Boolean = true,
assertion: RegionTraceSubject.() -> Unit
) {
- val assertionData =
- buildLayersVisibleRegionAssertion(
- componentMatcher,
- useCompositionEngineRegionOnly,
- assertion
- )
- doRunAssertion(assertionData)
+ withPerfettoTrace("assertLayersVisibleRegion") {
+ val assertionData =
+ buildLayersVisibleRegionAssertion(
+ componentMatcher,
+ useCompositionEngineRegionOnly,
+ assertion
+ )
+ doRunAssertion(assertionData)
+ }
}
/**
@@ -192,12 +222,14 @@
* @param assertion Assertion predicate
*/
fun assertEventLog(assertion: EventLogSubject.() -> Unit) {
- val assertionData =
- eventLogAssertionFactory.createTagAssertion(
- AssertionTag.ALL,
- assertion as FlickerSubject.() -> Unit
- )
- doRunAssertion(assertionData)
+ withPerfettoTrace("assertEventLog") {
+ val assertionData =
+ eventLogAssertionFactory.createTagAssertion(
+ AssertionTag.ALL,
+ assertion as FlickerSubject.() -> Unit
+ )
+ doRunAssertion(assertionData)
+ }
}
private fun doRunAssertion(assertion: AssertionData) {
diff --git a/libraries/flicker/src/com/android/server/wm/flicker/helpers/StandardAppHelper.kt b/libraries/flicker/src/com/android/server/wm/flicker/helpers/StandardAppHelper.kt
index 084ecc0..7913f96 100644
--- a/libraries/flicker/src/com/android/server/wm/flicker/helpers/StandardAppHelper.kt
+++ b/libraries/flicker/src/com/android/server/wm/flicker/helpers/StandardAppHelper.kt
@@ -34,6 +34,7 @@
import com.android.server.wm.traces.common.WindowManagerConditionsFactory
import com.android.server.wm.traces.common.windowmanager.WindowManagerState
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import com.android.server.wm.traces.parser.withPerfettoTrace
/**
* Class to take advantage of {@code IAppHelper} interface so the same test can be run against first
@@ -102,14 +103,18 @@
/** {@inheritDoc} */
override fun exit() {
- // Ensure all testing components end up being closed.
- activityManager?.forceStopPackage(packageName)
+ withPerfettoTrace("exit") {
+ // Ensure all testing components end up being closed.
+ activityManager?.forceStopPackage(packageName)
+ }
}
/** Exits the activity and wait for activity destroyed */
fun exit(wmHelper: WindowManagerStateHelper) {
- exit()
- waitForActivityDestroyed(wmHelper)
+ withPerfettoTrace("${this::class.simpleName}#exitAndWait") {
+ exit()
+ waitForActivityDestroyed(wmHelper)
+ }
}
/** Waits the activity until state change to {link WindowManagerState.STATE_DESTROYED} */
@@ -134,10 +139,12 @@
action: String? = null,
stringExtras: Map<String, String> = mapOf()
) {
- val intent = openAppIntent
- intent.action = action
- stringExtras.forEach { intent.putExtra(it.key, it.value) }
- context.startActivity(intent)
+ withPerfettoTrace("${this::class.simpleName}#launchAppViaIntent") {
+ val intent = openAppIntent
+ intent.action = action
+ stringExtras.forEach { intent.putExtra(it.key, it.value) }
+ context.startActivity(intent)
+ }
}
/**
@@ -188,31 +195,40 @@
waitConditions: Array<Condition<DeviceStateDump>> = emptyArray()
) {
launchAppViaIntent(action, stringExtras)
+ doWaitShown(wmHelper, expectedWindowName, waitConditions)
+ }
- val expectedWindow =
- if (expectedWindowName.isNotEmpty()) {
- ComponentNameMatcher("", expectedWindowName)
- } else {
- componentMatcher
+ private fun doWaitShown(
+ wmHelper: WindowManagerStateHelper,
+ expectedWindowName: String = "",
+ waitConditions: Array<Condition<DeviceStateDump>> = emptyArray()
+ ) {
+ withPerfettoTrace("${this::class.simpleName}#doWaitShown") {
+ val expectedWindow =
+ if (expectedWindowName.isNotEmpty()) {
+ ComponentNameMatcher("", expectedWindowName)
+ } else {
+ componentMatcher
+ }
+ val builder =
+ wmHelper
+ .StateSyncBuilder()
+ .add(WindowManagerConditionsFactory.isWMStateComplete())
+ .withAppTransitionIdle()
+ .withWindowSurfaceAppeared(expectedWindow)
+
+ waitConditions.forEach { builder.add(it) }
+ builder.waitForAndVerify()
+
+ // During seamless rotation the app window is shown
+ val currWmState = wmHelper.currentState.wmState
+ if (currWmState.visibleWindows.none { it.isFullscreen }) {
+ wmHelper
+ .StateSyncBuilder()
+ .withNavOrTaskBarVisible()
+ .withStatusBarVisible()
+ .waitForAndVerify()
}
- val builder =
- wmHelper
- .StateSyncBuilder()
- .add(WindowManagerConditionsFactory.isWMStateComplete())
- .withAppTransitionIdle()
- .withWindowSurfaceAppeared(expectedWindow)
-
- waitConditions.forEach { builder.add(it) }
- builder.waitForAndVerify()
-
- // During seamless rotation the app window is shown
- val currWmState = wmHelper.currentState.wmState
- if (currWmState.visibleWindows.none { it.isFullscreen }) {
- wmHelper
- .StateSyncBuilder()
- .withNavOrTaskBarVisible()
- .withStatusBarVisible()
- .waitForAndVerify()
}
}
diff --git a/libraries/flicker/src/com/android/server/wm/flicker/io/ResultWriter.kt b/libraries/flicker/src/com/android/server/wm/flicker/io/ResultWriter.kt
index 2901e66..e58b699 100644
--- a/libraries/flicker/src/com/android/server/wm/flicker/io/ResultWriter.kt
+++ b/libraries/flicker/src/com/android/server/wm/flicker/io/ResultWriter.kt
@@ -23,6 +23,7 @@
import com.android.server.wm.flicker.now
import com.android.server.wm.traces.common.IScenario
import com.android.server.wm.traces.common.Timestamp
+import com.android.server.wm.traces.parser.withPerfettoTrace
import java.io.BufferedInputStream
import java.io.BufferedOutputStream
import java.io.File
@@ -106,31 +107,32 @@
/** @return writes the result artifact to disk and returns it */
open fun write(): ResultData {
- val outputDir = outputDir
- requireNotNull(outputDir) { "Output dir not configured" }
- require(!scenario.isEmpty) { "Scenario shouldn't be empty" }
+ return withPerfettoTrace("write") {
+ val outputDir = outputDir
+ requireNotNull(outputDir) { "Output dir not configured" }
+ require(!scenario.isEmpty) { "Scenario shouldn't be empty" }
+ // Ensure output directory exists
+ outputDir.toFile().mkdirs()
- // Ensure output directory exists
- outputDir.toFile().mkdirs()
-
- if (runStatus == RunStatus.UNDEFINED) {
- Log.w(FLICKER_IO_TAG, "Writing result with $runStatus run status")
- }
-
- val newFileName = "${runStatus.prefix}_$scenario.zip"
- val dstFile = outputDir.resolve(newFileName)
- Log.d(FLICKER_IO_TAG, "Writing artifact file $dstFile")
- createZipFile(dstFile.toFile()).use { zipOutputStream ->
- files.forEach { (descriptor, file) ->
- addFile(zipOutputStream, file, nameInArchive = descriptor.fileNameInArtifact)
+ if (runStatus == RunStatus.UNDEFINED) {
+ Log.w(FLICKER_IO_TAG, "Writing result with $runStatus run status")
}
- }
- return ResultData(
- dstFile,
- TransitionTimeRange(transitionStartTime, transitionEndTime),
- executionError,
- runStatus
- )
+ val newFileName = "${runStatus.prefix}_$scenario.zip"
+ val dstFile = outputDir.resolve(newFileName)
+ Log.d(FLICKER_IO_TAG, "Writing artifact file $dstFile")
+ createZipFile(dstFile.toFile()).use { zipOutputStream ->
+ files.forEach { (descriptor, file) ->
+ addFile(zipOutputStream, file, nameInArchive = descriptor.fileNameInArtifact)
+ }
+ }
+
+ ResultData(
+ dstFile,
+ TransitionTimeRange(transitionStartTime, transitionEndTime),
+ executionError,
+ runStatus
+ )
+ }
}
}
diff --git a/libraries/flicker/src/com/android/server/wm/flicker/junit/FlickerServiceDecorator.kt b/libraries/flicker/src/com/android/server/wm/flicker/junit/FlickerServiceDecorator.kt
index 56b027c..595d068 100644
--- a/libraries/flicker/src/com/android/server/wm/flicker/junit/FlickerServiceDecorator.kt
+++ b/libraries/flicker/src/com/android/server/wm/flicker/junit/FlickerServiceDecorator.kt
@@ -30,7 +30,7 @@
import com.android.server.wm.flicker.service.FlickerService
import com.android.server.wm.flicker.service.FlickerServiceResultsCollector
import com.android.server.wm.flicker.service.assertors.AssertionResult
-import kotlin.system.measureTimeMillis
+import com.android.server.wm.traces.parser.withPerfettoTrace
import org.junit.runner.Description
import org.junit.runners.model.FrameworkMethod
import org.junit.runners.model.Statement
@@ -76,8 +76,10 @@
override fun getTestMethods(test: Any): List<FrameworkMethod> {
val result = inner?.getTestMethods(test)?.toMutableList() ?: mutableListOf()
if (shouldComputeTestMethods()) {
- measureTimeMillis { result.addAll(computeFlickerServiceTests(test)) }
- .also { Log.d(FLICKER_TAG, "Took ${it}ms to compute ${result.size} flicker tests") }
+ withPerfettoTrace("getTestMethods") {
+ result.addAll(computeFlickerServiceTests(test))
+ Log.d(FLICKER_TAG, "Computed ${result.size} flicker tests")
+ }
}
return result
}
diff --git a/libraries/flicker/src/com/android/server/wm/flicker/rules/ChangeDisplayOrientationRule.kt b/libraries/flicker/src/com/android/server/wm/flicker/rules/ChangeDisplayOrientationRule.kt
index 76ac260..46a1658 100644
--- a/libraries/flicker/src/com/android/server/wm/flicker/rules/ChangeDisplayOrientationRule.kt
+++ b/libraries/flicker/src/com/android/server/wm/flicker/rules/ChangeDisplayOrientationRule.kt
@@ -26,6 +26,7 @@
import com.android.server.wm.flicker.FLICKER_TAG
import com.android.server.wm.traces.common.service.PlatformConsts
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import com.android.server.wm.traces.parser.withPerfettoTrace
import org.junit.rules.TestWatcher
import org.junit.runner.Description
@@ -49,18 +50,23 @@
private var initialOrientation = PlatformConsts.Rotation.ROTATION_0
override fun starting(description: Description?) {
- Log.v(
- FLICKER_TAG,
- "Changing display orientation to " +
- "$targetOrientation ${targetOrientation.description}"
- )
- val wm = instrumentation.context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
- initialOrientation = PlatformConsts.Rotation.getByValue(wm.defaultDisplay.rotation)
- setRotation(targetOrientation, instrumentation, clearCacheAfterParsing)
+ withPerfettoTrace("ChangeDisplayOrientationRule:starting") {
+ Log.v(
+ FLICKER_TAG,
+ "Changing display orientation to " +
+ "$targetOrientation ${targetOrientation.description}"
+ )
+ val wm =
+ instrumentation.context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
+ initialOrientation = PlatformConsts.Rotation.getByValue(wm.defaultDisplay.rotation)
+ setRotation(targetOrientation, instrumentation, clearCacheAfterParsing)
+ }
}
override fun finished(description: Description?) {
- setRotation(initialOrientation, instrumentation, clearCacheAfterParsing)
+ withPerfettoTrace("ChangeDisplayOrientationRule:finished") {
+ setRotation(initialOrientation, instrumentation, clearCacheAfterParsing)
+ }
}
companion object {
diff --git a/libraries/flicker/src/com/android/server/wm/flicker/rules/LaunchAppRule.kt b/libraries/flicker/src/com/android/server/wm/flicker/rules/LaunchAppRule.kt
index 669fc8d..239e5f6 100644
--- a/libraries/flicker/src/com/android/server/wm/flicker/rules/LaunchAppRule.kt
+++ b/libraries/flicker/src/com/android/server/wm/flicker/rules/LaunchAppRule.kt
@@ -23,6 +23,7 @@
import com.android.server.wm.flicker.helpers.StandardAppHelper
import com.android.server.wm.traces.common.ComponentNameMatcher
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import com.android.server.wm.traces.parser.withPerfettoTrace
import org.junit.rules.TestWatcher
import org.junit.runner.Description
@@ -62,8 +63,10 @@
)
override fun starting(description: Description?) {
- Log.v(FLICKER_TAG, "Launching app $appHelper")
- appHelper.launchViaIntent()
- appHelper.exit(wmHelper)
+ withPerfettoTrace("LaunchAppRule:finished") {
+ Log.v(FLICKER_TAG, "Launching app $appHelper")
+ appHelper.launchViaIntent()
+ appHelper.exit(wmHelper)
+ }
}
}
diff --git a/libraries/flicker/src/com/android/server/wm/flicker/rules/RemoveAllTasksButHomeRule.kt b/libraries/flicker/src/com/android/server/wm/flicker/rules/RemoveAllTasksButHomeRule.kt
index 92192cb..d96b0a6 100644
--- a/libraries/flicker/src/com/android/server/wm/flicker/rules/RemoveAllTasksButHomeRule.kt
+++ b/libraries/flicker/src/com/android/server/wm/flicker/rules/RemoveAllTasksButHomeRule.kt
@@ -20,14 +20,17 @@
import android.app.WindowConfiguration
import android.util.Log
import com.android.server.wm.flicker.FLICKER_TAG
+import com.android.server.wm.traces.parser.withPerfettoTrace
import org.junit.rules.TestWatcher
import org.junit.runner.Description
/** Test rule to ensure no tasks as running before executing the test */
class RemoveAllTasksButHomeRule() : TestWatcher() {
override fun starting(description: Description?) {
- Log.v(FLICKER_TAG, "Removing all tasks (except home)")
- removeAllTasksButHome()
+ withPerfettoTrace("RemoveAllTasksButHomeRule:finished") {
+ Log.v(FLICKER_TAG, "Removing all tasks (except home)")
+ removeAllTasksButHome()
+ }
}
companion object {
diff --git a/libraries/flicker/src/com/android/server/wm/flicker/runner/SetupTeardownRule.kt b/libraries/flicker/src/com/android/server/wm/flicker/runner/SetupTeardownRule.kt
index b3ef438..8d0f5fd 100644
--- a/libraries/flicker/src/com/android/server/wm/flicker/runner/SetupTeardownRule.kt
+++ b/libraries/flicker/src/com/android/server/wm/flicker/runner/SetupTeardownRule.kt
@@ -17,11 +17,11 @@
package com.android.server.wm.flicker.runner
import android.app.Instrumentation
-import android.util.Log
import com.android.server.wm.flicker.IFlickerTestData
import com.android.server.wm.flicker.io.ResultWriter
import com.android.server.wm.traces.common.IScenario
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import com.android.server.wm.traces.parser.withPerfettoTrace
import org.junit.rules.TestRule
import org.junit.runner.Description
import org.junit.runners.model.Statement
@@ -61,8 +61,8 @@
@Throws(TransitionSetupFailure::class)
private fun doRunTransitionSetup(description: Description?) {
- Log.d(FLICKER_RUNNER_TAG, "doRunTransitionSetup")
- Utils.executeAndNotifyRunner(scenario, "Running transition setup for $description") {
+ withPerfettoTrace("doRunTransitionSetup") {
+ Utils.notifyRunnerProgress(scenario, "Running transition setup for $description")
try {
setupCommands.forEach { it.invoke(flicker) }
Utils.doWaitForUiStabilize(wmHelper)
@@ -74,8 +74,8 @@
@Throws(TransitionTeardownFailure::class)
private fun doRunTransitionTeardown(description: Description?) {
- Log.d(FLICKER_RUNNER_TAG, "doRunTransitionTeardown")
- Utils.executeAndNotifyRunner(scenario, "Running transition teardown for $description") {
+ withPerfettoTrace("doRunTransitionTeardown") {
+ Utils.notifyRunnerProgress(scenario, "Running transition teardown for $description")
try {
teardownCommands.forEach { it.invoke(flicker) }
Utils.doWaitForUiStabilize(wmHelper)
diff --git a/libraries/flicker/src/com/android/server/wm/flicker/runner/TraceMonitorRule.kt b/libraries/flicker/src/com/android/server/wm/flicker/runner/TraceMonitorRule.kt
index 6b313df..b778fce 100644
--- a/libraries/flicker/src/com/android/server/wm/flicker/runner/TraceMonitorRule.kt
+++ b/libraries/flicker/src/com/android/server/wm/flicker/runner/TraceMonitorRule.kt
@@ -23,6 +23,7 @@
import com.android.server.wm.flicker.io.ResultWriter
import com.android.server.wm.traces.common.IScenario
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import com.android.server.wm.traces.parser.withPerfettoTrace
import org.junit.rules.TestRule
import org.junit.runner.Description
import org.junit.runners.model.Statement
@@ -57,8 +58,8 @@
}
private fun doStartMonitors(description: Description?) {
- Log.d(FLICKER_RUNNER_TAG, "doStartMonitors")
- Utils.executeAndNotifyRunner(scenario, "Starting traces for $description") {
+ withPerfettoTrace("doStartMonitors") {
+ Utils.notifyRunnerProgress(scenario, "Starting traces for $description")
traceMonitors.forEach {
try {
it.start()
@@ -70,8 +71,8 @@
}
private fun doStopMonitors(description: Description?) {
- Log.d(FLICKER_RUNNER_TAG, "doStopMonitors")
- Utils.executeAndNotifyRunner(scenario, "Stopping traces for $description") {
+ withPerfettoTrace("doStopMonitors") {
+ Utils.notifyRunnerProgress(scenario, "Stopping traces for $description")
val errors =
traceMonitors.map {
runCatching {
diff --git a/libraries/flicker/src/com/android/server/wm/flicker/runner/TransitionExecutionRule.kt b/libraries/flicker/src/com/android/server/wm/flicker/runner/TransitionExecutionRule.kt
index 7c745d3..f25894e 100644
--- a/libraries/flicker/src/com/android/server/wm/flicker/runner/TransitionExecutionRule.kt
+++ b/libraries/flicker/src/com/android/server/wm/flicker/runner/TransitionExecutionRule.kt
@@ -24,6 +24,7 @@
import com.android.server.wm.traces.common.IScenario
import com.android.server.wm.traces.parser.getCurrentState
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import com.android.server.wm.traces.parser.withPerfettoTrace
import java.nio.file.Files
import org.junit.rules.TestRule
import org.junit.runner.Description
@@ -52,27 +53,29 @@
override fun apply(base: Statement?, description: Description?): Statement {
return object : Statement() {
override fun evaluate() {
- try {
- Utils.executeAndNotifyRunner(scenario, "Running transition $description") {
+ withPerfettoTrace("transition") {
+ try {
+ Utils.notifyRunnerProgress(scenario, "Running transition $description")
doRunBeforeTransition()
commands.forEach { it.invoke(flicker) }
base?.evaluate()
+ } catch (e: Throwable) {
+ throw if (e is AssertionError) {
+ e
+ } else {
+ TransitionExecutionFailure(e)
+ }
+ } finally {
+ doRunAfterTransition()
}
- } catch (e: Throwable) {
- throw if (e is AssertionError) {
- e
- } else {
- TransitionExecutionFailure(e)
- }
- } finally {
- doRunAfterTransition()
}
}
}
}
private fun doRunBeforeTransition() {
- Utils.executeAndNotifyRunner(scenario, "Running doRunBeforeTransition") {
+ withPerfettoTrace("doRunBeforeTransition") {
+ Utils.notifyRunnerProgress(scenario, "Running doRunBeforeTransition")
Log.d(FLICKER_RUNNER_TAG, "doRunBeforeTransition")
resultWriter.setTransitionStartTime()
flicker.setCreateTagListener { doCreateTag(it) }
@@ -81,7 +84,8 @@
}
private fun doRunAfterTransition() {
- Utils.executeAndNotifyRunner(scenario, "Running doRunAfterTransition") {
+ withPerfettoTrace("doRunAfterTransition") {
+ Utils.notifyRunnerProgress(scenario, "Running doRunAfterTransition")
Log.d(FLICKER_RUNNER_TAG, "doRunAfterTransition")
Utils.doWaitForUiStabilize(wmHelper)
resultWriter.setTransitionEndTime()
@@ -100,7 +104,8 @@
}
private fun doCreateTag(tag: String) {
- Utils.executeAndNotifyRunner(scenario, "Creating tag $tag") {
+ withPerfettoTrace("doRunAfterTransition") {
+ Utils.notifyRunnerProgress(scenario, "Creating tag $tag")
doValidateTag(tag)
tags.add(tag)
diff --git a/libraries/flicker/src/com/android/server/wm/flicker/runner/TransitionRunner.kt b/libraries/flicker/src/com/android/server/wm/flicker/runner/TransitionRunner.kt
index 13fa708..3fcd047 100644
--- a/libraries/flicker/src/com/android/server/wm/flicker/runner/TransitionRunner.kt
+++ b/libraries/flicker/src/com/android/server/wm/flicker/runner/TransitionRunner.kt
@@ -29,6 +29,7 @@
import com.android.server.wm.flicker.rules.LaunchAppRule
import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule
import com.android.server.wm.traces.common.IScenario
+import com.android.server.wm.traces.parser.withPerfettoTrace
import org.junit.rules.RuleChain
import org.junit.runner.Description
@@ -43,16 +44,18 @@
) {
/** Executes [flicker] transition and returns the result */
fun execute(flicker: IFlickerTestData, description: Description?): ResultData {
- resultWriter.forScenario(scenario).withOutputDir(flicker.outputDir)
+ return withPerfettoTrace("TransitionRunner:execute") {
+ resultWriter.forScenario(scenario).withOutputDir(flicker.outputDir)
- val ruleChain = buildTestRuleChain(flicker)
- try {
- ruleChain.apply(/* statement */ null, description).evaluate()
- resultWriter.setRunComplete()
- } catch (e: Throwable) {
- resultWriter.setRunFailed(e)
+ val ruleChain = buildTestRuleChain(flicker)
+ try {
+ ruleChain.apply(/* statement */ null, description).evaluate()
+ resultWriter.setRunComplete()
+ } catch (e: Throwable) {
+ resultWriter.setRunFailed(e)
+ }
+ resultWriter.write()
}
- return resultWriter.write()
}
/**
diff --git a/libraries/flicker/src/com/android/server/wm/flicker/runner/Utils.kt b/libraries/flicker/src/com/android/server/wm/flicker/runner/Utils.kt
index f0a9985..41b3ec9 100644
--- a/libraries/flicker/src/com/android/server/wm/flicker/runner/Utils.kt
+++ b/libraries/flicker/src/com/android/server/wm/flicker/runner/Utils.kt
@@ -24,7 +24,6 @@
import com.android.server.wm.traces.common.IScenario
import com.android.server.wm.traces.common.WindowManagerConditionsFactory
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
-import kotlin.system.measureTimeMillis
/** Helper class for flicker transition rules */
object Utils {
@@ -41,22 +40,11 @@
)
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
- /** Execute [predicate] and log [logMessage] in logcat and notify the host side runner */
- internal fun executeAndNotifyRunner(
- scenario: IScenario,
- logMessage: String,
- predicate: () -> Unit
- ) {
- notifyRunnerProgress(scenario, logMessage)
- measureTimeMillis { predicate() }
- .also { notifyRunnerProgress(scenario, "\tDuration ${it}ms") }
- }
-
internal fun doWaitForUiStabilize(wmHelper: WindowManagerStateHelper) {
wmHelper.StateSyncBuilder().add(UI_STABLE_CONDITIONS).waitFor()
}
- private fun notifyRunnerProgress(scenario: IScenario, msg: String) {
+ internal fun notifyRunnerProgress(scenario: IScenario, msg: String) {
Log.d(FLICKER_RUNNER_TAG, "${scenario.key} - $msg")
val results = Bundle()
results.putString(Instrumentation.REPORT_KEY_STREAMRESULT, "$msg\n")
diff --git a/libraries/flicker/src/com/android/server/wm/traces/common/WaitCondition.kt b/libraries/flicker/src/com/android/server/wm/traces/common/WaitCondition.kt
index d7ef0bd..bd58870 100644
--- a/libraries/flicker/src/com/android/server/wm/traces/common/WaitCondition.kt
+++ b/libraries/flicker/src/com/android/server/wm/traces/common/WaitCondition.kt
@@ -50,31 +50,66 @@
@JsName("onLog") private val onLog: ((String, Boolean) -> Unit)?,
@JsName("onFailure") private val onFailure: ((T) -> Any)?,
@JsName("onRetry") private val onRetry: ((T) -> Any)?,
- @JsName("onSuccess") private val onSuccess: ((T) -> Any)?
+ @JsName("onSuccess") private val onSuccess: ((T) -> Any)?,
+ @JsName("onStart") private val onStart: ((String) -> Any)?,
+ @JsName("onEnd") private val onEnd: (() -> Any)?
) {
/** @return `false` if the condition does not satisfy within the time limit. */
@JsName("waitFor")
fun waitFor(): Boolean {
+ onStart?.invoke("waitFor")
+ try {
+ return doWaitFor()
+ } finally {
+ onEnd?.invoke()
+ }
+ }
+
+ private fun doWaitFor(): Boolean {
onLog?.invoke("***Waiting for $condition", /* isError */ false)
var currState: T? = null
+ var success = false
for (i in 0..retryLimit) {
- currState = supplier.invoke()
- if (condition.isSatisfied(currState)) {
- onLog?.invoke("***Waiting for $condition ... Success!", /* isError */ false)
- onSuccess?.invoke(currState)
- return true
- } else {
- val detailedMessage = condition.getMessage(currState)
- onLog?.invoke(
- "***Waiting for $detailedMessage... retry=${i + 1}",
- /* isError */ true
- )
- if (i < retryLimit) {
- onRetry?.invoke(currState)
- }
+ val result = doWaitForRetry(i)
+ success = result.first
+ currState = result.second
+ if (success) {
+ break
+ } else if (i < retryLimit) {
+ onRetry?.invoke(currState)
}
}
+ return if (success) {
+ true
+ } else {
+ doNotifyFailure(currState)
+ false
+ }
+ }
+
+ private fun doWaitForRetry(retryNr: Int): Pair<Boolean, T> {
+ onStart?.invoke("doWaitForRetry")
+ try {
+ val currState = supplier.invoke()
+ return if (condition.isSatisfied(currState)) {
+ onLog?.invoke("***Waiting for $condition ... Success!", /* isError */ false)
+ onSuccess?.invoke(currState)
+ Pair(true, currState)
+ } else {
+ val detailedMessage = condition.getMessage(currState)
+ onLog?.invoke(
+ "***Waiting for $detailedMessage... retry=${retryNr + 1}",
+ /* isError */ true
+ )
+ Pair(false, currState)
+ }
+ } finally {
+ onEnd?.invoke()
+ }
+ }
+
+ private fun doNotifyFailure(currState: T?) {
val detailedMessage =
if (currState != null) {
condition.getMessage(currState)
@@ -86,7 +121,6 @@
require(currState != null) { "Missing last result for failure notification" }
onFailure.invoke(currState)
}
- return false
}
class Builder<T>(
@@ -94,6 +128,8 @@
@JsName("retryLimit") private var retryLimit: Int
) {
@JsName("conditions") private val conditions = mutableListOf<Condition<T>>()
+ private var onStart: ((String) -> Any)? = null
+ private var onEnd: (() -> Any)? = null
private var onFailure: ((T) -> Any)? = null
private var onRetry: ((T) -> Any)? = null
private var onSuccess: ((T) -> Any)? = null
@@ -130,6 +166,14 @@
@JsName("onRetry")
fun onRetry(onRetry: ((T) -> Any)? = null): Builder<T> = apply { this.onRetry = onRetry }
+ @JsName("onStart")
+ fun onStart(onStart: ((String) -> Any)? = null): Builder<T> = apply {
+ this.onStart = onStart
+ }
+
+ @JsName("onEnd")
+ fun onEnd(onEnd: (() -> Any)? = null): Builder<T> = apply { this.onEnd = onEnd }
+
@JsName("onSuccess")
fun onSuccess(onRetry: ((T) -> Any)? = null): Builder<T> = apply {
this.onSuccess = onRetry
@@ -144,7 +188,9 @@
onLog,
onFailure,
onRetry,
- onSuccess
+ onSuccess,
+ onStart,
+ onEnd
)
}
diff --git a/libraries/flicker/src/com/android/server/wm/traces/parser/AbstractParser.kt b/libraries/flicker/src/com/android/server/wm/traces/parser/AbstractParser.kt
index 0f6c61f..f11cf6a 100644
--- a/libraries/flicker/src/com/android/server/wm/traces/parser/AbstractParser.kt
+++ b/libraries/flicker/src/com/android/server/wm/traces/parser/AbstractParser.kt
@@ -16,9 +16,7 @@
package com.android.server.wm.traces.parser
-import android.util.Log
import com.android.server.wm.traces.common.Cache
-import kotlin.system.measureTimeMillis
/** Base parser class */
abstract class AbstractParser<InputTypeTrace, OutputTypeTrace> {
@@ -44,26 +42,20 @@
* @param clearCache If the caching used while parsing the object should be cleared
*/
open fun parse(input: InputTypeTrace, clearCache: Boolean): OutputTypeTrace {
- return try {
- logTime("Parsing objects") { doParse(input) }
- } finally {
- if (clearCache) {
- Cache.clear()
+ return withPerfettoTrace("${this::class.simpleName}#parse") {
+ try {
+ doParse(input)
+ } finally {
+ if (clearCache) {
+ Cache.clear()
+ }
}
}
}
protected fun decodeByteArray(input: ByteArray): InputTypeTrace {
- return logTime("Decoding $traceName proto file") { doDecodeByteArray(input) }
- }
-
- protected fun <T> logTime(msg: String, predicate: () -> T): T {
- var data: T?
- measureTimeMillis { data = predicate() }.also { Log.v(LOG_TAG_TIME, "$msg: ${it}ms") }
- return data ?: error("Unable to process")
- }
-
- companion object {
- private const val LOG_TAG_TIME = "$LOG_TAG-Duration"
+ return withPerfettoTrace("${this::class.simpleName}#decodeByteArray") {
+ doDecodeByteArray(input)
+ }
}
}
diff --git a/libraries/flicker/src/com/android/server/wm/traces/parser/AbstractTraceParser.kt b/libraries/flicker/src/com/android/server/wm/traces/parser/AbstractTraceParser.kt
index 3e86793..841a627 100644
--- a/libraries/flicker/src/com/android/server/wm/traces/parser/AbstractTraceParser.kt
+++ b/libraries/flicker/src/com/android/server/wm/traces/parser/AbstractTraceParser.kt
@@ -80,8 +80,7 @@
if (!selectedInputTimestamps.contains(currTimestamp) || !shouldParseEntry(rawEntry)) {
continue
}
- val parsedEntry =
- logTime("Creating entry for time $currTimestamp") { doParseEntry(rawEntry) }
+ val parsedEntry = withPerfettoTrace("doParseEntry") { doParseEntry(rawEntry) }
parsedEntries.add(parsedEntry)
}
return createTrace(parsedEntries)
@@ -103,11 +102,13 @@
addInitialEntry: Boolean = true,
clearCache: Boolean = true
): OutputTypeTrace {
- return try {
- logTime("Parsing objects") { doParse(input, from, to, addInitialEntry) }
- } finally {
- if (clearCache) {
- Cache.clear()
+ return withPerfettoTrace("${this::class.simpleName}#parse") {
+ try {
+ doParse(input, from, to, addInitialEntry)
+ } finally {
+ if (clearCache) {
+ Cache.clear()
+ }
}
}
}
diff --git a/libraries/flicker/src/com/android/server/wm/traces/parser/DeviceDumpParser.kt b/libraries/flicker/src/com/android/server/wm/traces/parser/DeviceDumpParser.kt
index 07a63ca..eb8edee 100644
--- a/libraries/flicker/src/com/android/server/wm/traces/parser/DeviceDumpParser.kt
+++ b/libraries/flicker/src/com/android/server/wm/traces/parser/DeviceDumpParser.kt
@@ -51,24 +51,26 @@
layersTraceData: ByteArray,
clearCacheAfterParsing: Boolean
): NullableDeviceStateDump {
- return NullableDeviceStateDump(
- wmState =
- if (wmTraceData.isNotEmpty()) {
- WindowManagerDumpParser()
- .parse(wmTraceData, clearCache = clearCacheAfterParsing)
- .first()
- } else {
- null
- },
- layerState =
- if (layersTraceData.isNotEmpty()) {
- LayersTraceParser()
- .parse(layersTraceData, clearCache = clearCacheAfterParsing)
- .first()
- } else {
- null
- }
- )
+ return withPerfettoTrace("fromNullableDump") {
+ NullableDeviceStateDump(
+ wmState =
+ if (wmTraceData.isNotEmpty()) {
+ WindowManagerDumpParser()
+ .parse(wmTraceData, clearCache = clearCacheAfterParsing)
+ .first()
+ } else {
+ null
+ },
+ layerState =
+ if (layersTraceData.isNotEmpty()) {
+ LayersTraceParser()
+ .parse(layersTraceData, clearCache = clearCacheAfterParsing)
+ .first()
+ } else {
+ null
+ }
+ )
+ }
}
/** See [fromNullableDump] */
@@ -78,12 +80,14 @@
layersTraceData: ByteArray,
clearCacheAfterParsing: Boolean
): DeviceStateDump {
- val nullableDump =
- fromNullableDump(wmTraceData, layersTraceData, clearCacheAfterParsing)
- return DeviceStateDump(
- nullableDump.wmState ?: error("WMState dump missing"),
- nullableDump.layerState ?: error("Layer State dump missing")
- )
+ return withPerfettoTrace("fromDump") {
+ val nullableDump =
+ fromNullableDump(wmTraceData, layersTraceData, clearCacheAfterParsing)
+ DeviceStateDump(
+ nullableDump.wmState ?: error("WMState dump missing"),
+ nullableDump.layerState ?: error("Layer State dump missing")
+ )
+ }
}
/**
@@ -104,20 +108,22 @@
layersTraceData: ByteArray,
clearCache: Boolean
): DeviceTraceDump {
- return DeviceTraceDump(
- wmTrace =
- if (wmTraceData.isNotEmpty()) {
- WindowManagerTraceParser().parse(wmTraceData, clearCache = clearCache)
- } else {
- null
- },
- layersTrace =
- if (layersTraceData.isNotEmpty()) {
- LayersTraceParser().parse(layersTraceData, clearCache = clearCache)
- } else {
- null
- }
- )
+ return withPerfettoTrace("fromTrace") {
+ DeviceTraceDump(
+ wmTrace =
+ if (wmTraceData.isNotEmpty()) {
+ WindowManagerTraceParser().parse(wmTraceData, clearCache = clearCache)
+ } else {
+ null
+ },
+ layersTrace =
+ if (layersTraceData.isNotEmpty()) {
+ LayersTraceParser().parse(layersTraceData, clearCache = clearCache)
+ } else {
+ null
+ }
+ )
+ }
}
}
}
diff --git a/libraries/flicker/src/com/android/server/wm/traces/parser/Extensions.kt b/libraries/flicker/src/com/android/server/wm/traces/parser/Extensions.kt
index 30b4015..3e2fd99 100644
--- a/libraries/flicker/src/com/android/server/wm/traces/parser/Extensions.kt
+++ b/libraries/flicker/src/com/android/server/wm/traces/parser/Extensions.kt
@@ -21,6 +21,7 @@
import android.app.UiAutomation
import android.content.ComponentName
import android.os.ParcelFileDescriptor
+import android.os.Trace
import android.util.Log
import com.android.server.wm.traces.common.ComponentNameMatcher
import com.android.server.wm.traces.common.DeviceStateDump
@@ -120,6 +121,15 @@
)
}
+fun <T> withPerfettoTrace(logMsg: String, predicate: () -> T): T {
+ return try {
+ Trace.beginSection(logMsg)
+ predicate()
+ } finally {
+ Trace.endSection()
+ }
+}
+
/** Converts an Android [ComponentName] into a flicker [ComponentNameMatcher] */
fun ComponentName.toFlickerComponent(): ComponentNameMatcher =
ComponentNameMatcher(this.packageName, this.className)
diff --git a/libraries/flicker/src/com/android/server/wm/traces/parser/windowmanager/WindowManagerStateHelper.kt b/libraries/flicker/src/com/android/server/wm/traces/parser/windowmanager/WindowManagerStateHelper.kt
index f038bf6..d71c6e7 100644
--- a/libraries/flicker/src/com/android/server/wm/traces/parser/windowmanager/WindowManagerStateHelper.kt
+++ b/libraries/flicker/src/com/android/server/wm/traces/parser/windowmanager/WindowManagerStateHelper.kt
@@ -20,6 +20,7 @@
import android.app.Instrumentation
import android.app.WindowConfiguration
import android.os.SystemClock
+import android.os.Trace
import android.util.Log
import android.view.Display
import androidx.test.platform.app.InstrumentationRegistry
@@ -112,6 +113,8 @@
private fun createConditionBuilder(): WaitCondition.Builder<DeviceStateDump> =
WaitCondition.Builder(deviceDumpSupplier, numRetries)
+ .onStart { Trace.beginSection(it) }
+ .onEnd { Trace.endSection() }
.onSuccess { updateCurrState(it) }
.onFailure { updateCurrState(it) }
.onLog { msg, isError ->