Test for tracing at app startup

Bug: 283786690
Test: TrivialStartupBenchmark
Change-Id: I670cfd34a490a2e51d2ee3a10fcb84f6bab47c9c
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Arguments.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Arguments.kt
index 50b3f6b..47a2342 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Arguments.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Arguments.kt
@@ -50,7 +50,14 @@
      *
      * Currently internal/experimental
      */
-    val fullTracingEnable: Boolean
+    private val _fullTracingEnable: Boolean
+    val fullTracingEnable: Boolean get() = fullTracingEnableOverride ?: _fullTracingEnable
+
+    /**
+     * Allows tests to override whether full tracing is enabled
+     */
+    @VisibleForTesting
+    var fullTracingEnableOverride: Boolean? = null
 
     val enabledRules: Set<RuleType>
 
@@ -121,7 +128,7 @@
         iterations =
             arguments.getBenchmarkArgument("iterations")?.toInt()
 
-        fullTracingEnable =
+        _fullTracingEnable =
             (arguments.getBenchmarkArgument("fullTracing.enable")?.toBoolean() ?: false)
 
         // Transform comma-delimited list into set of suppressed errors
diff --git a/compose/integration-tests/macrobenchmark-target/src/main/AndroidManifest.xml b/compose/integration-tests/macrobenchmark-target/src/main/AndroidManifest.xml
index 39a5d41..1b763e5 100644
--- a/compose/integration-tests/macrobenchmark-target/src/main/AndroidManifest.xml
+++ b/compose/integration-tests/macrobenchmark-target/src/main/AndroidManifest.xml
@@ -47,6 +47,19 @@
             </intent-filter>
         </activity>
         <activity
+            android:name=".TrivialStartupTracingActivity"
+            android:label="C TrivialTracing"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="androidx.compose.integration.macrobenchmark.target.TRIVIAL_STARTUP_TRACING_ACTIVITY" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+        <activity
             android:name=".FullyDrawnStartupActivity"
             android:exported="true">
             <intent-filter>
diff --git a/compose/integration-tests/macrobenchmark-target/src/main/java/androidx/compose/integration/macrobenchmark/target/TrivialStartupTracingActivity.kt b/compose/integration-tests/macrobenchmark-target/src/main/java/androidx/compose/integration/macrobenchmark/target/TrivialStartupTracingActivity.kt
new file mode 100644
index 0000000..a3f9cbc
--- /dev/null
+++ b/compose/integration-tests/macrobenchmark-target/src/main/java/androidx/compose/integration/macrobenchmark/target/TrivialStartupTracingActivity.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.integration.macrobenchmark.target
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.compose.material.Text
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+
+class TrivialStartupTracingActivity : ComponentActivity() {
+    private var incrementActivityResumedCount = {}
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        setContent {
+            var resumedCount by remember { mutableIntStateOf(0) }
+            incrementActivityResumedCount = { ++resumedCount }
+            Text("Compose Macrobenchmark Target (resumed $resumedCount times)")
+        }
+    }
+
+    override fun onResume() {
+        super.onResume()
+        incrementActivityResumedCount()
+    }
+}
diff --git a/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialStartupTracingBenchmark.kt b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialStartupTracingBenchmark.kt
new file mode 100644
index 0000000..47cbb44
--- /dev/null
+++ b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialStartupTracingBenchmark.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.integration.macrobenchmark
+
+import androidx.benchmark.Arguments
+import androidx.benchmark.macro.CompilationMode
+import androidx.benchmark.macro.ExperimentalMetricApi
+import androidx.benchmark.macro.StartupMode
+import androidx.benchmark.macro.TraceSectionMetric
+import androidx.benchmark.macro.junit4.MacrobenchmarkRule
+import androidx.test.filters.LargeTest
+import androidx.testutils.measureStartup
+import org.hamcrest.CoreMatchers.`is`
+import org.hamcrest.MatcherAssert.assertThat
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@OptIn(ExperimentalMetricApi::class)
+@LargeTest
+@RunWith(Parameterized::class)
+class TrivialStartupTracingBenchmark(
+    private val startupMode: StartupMode,
+    private val compilationMode: CompilationMode,
+    private val isFullTracingEnabled: Boolean
+) {
+    @get:Rule
+    val benchmarkRule = MacrobenchmarkRule()
+
+    // TODO(283953019): enable alongside StartupTracingInitializer (pending performance testing)
+    @Ignore
+    @Test
+    fun startup() = try {
+        Arguments.fullTracingEnableOverride = isFullTracingEnabled
+        assertThat(Arguments.fullTracingEnable, `is`(isFullTracingEnabled))
+
+        try {
+            val perfettoSdkTraceSection = TraceSectionMetric(
+                "androidx.compose.integration.macrobenchmark.target." +
+                    "TrivialStartupTracingActivity.onCreate.<anonymous>" +
+                    " (TrivialStartupTracingActivity.kt:33)"
+            )
+            benchmarkRule.measureStartup(
+                compilationMode = compilationMode,
+                startupMode = startupMode,
+                iterations = 1, // we are only verifying presence of entries (not the timing data)
+                metrics = listOf(perfettoSdkTraceSection),
+                packageName = "androidx.compose.integration.macrobenchmark.target"
+            ) {
+                action = "androidx.compose.integration.macrobenchmark.target." +
+                    "TRIVIAL_STARTUP_TRACING_ACTIVITY"
+            }
+        } catch (e: IllegalArgumentException) {
+            if (!isFullTracingEnabled &&
+                e.message?.contains("Unable to read any metrics during benchmark") == true
+            ) {
+                // this is expected, we don't expect Perfetto SDK Tracing section present
+                // when full tracing is disabled
+            } else throw e // this is a legitimate failure
+        }
+    } finally {
+        Arguments.fullTracingEnableOverride = null
+    }
+
+    companion object {
+        @Parameterized.Parameters(name = "startup={0},compilation={1},fullTracing={2}")
+        @JvmStatic
+        fun parameters() = listOf(
+            arrayOf(StartupMode.COLD, CompilationMode.DEFAULT, /* fullTracing = */ true),
+            arrayOf(StartupMode.COLD, CompilationMode.DEFAULT, /* fullTracing = */ false),
+            arrayOf(StartupMode.WARM, CompilationMode.DEFAULT, /* fullTracing = */ true),
+            arrayOf(StartupMode.WARM, CompilationMode.DEFAULT, /* fullTracing = */ false),
+        )
+    }
+}