Fix Androidx.tracing compat behavior, avoid class verification error
Fixes:204368464
Test: AndroidxTracingTraceTest on API 24
Note that the test can't run against tip of tree androidx.tracing long
term (and will have to revert to a stable dependency when benchmark
goes beta), but it's still useful for now.
Change-Id: I2b28acecd32e440c84f2814a5d748f047bfe9d68
diff --git a/benchmark/benchmark-macro/build.gradle b/benchmark/benchmark-macro/build.gradle
index 1a0de1c..ee51dc4 100644
--- a/benchmark/benchmark-macro/build.gradle
+++ b/benchmark/benchmark-macro/build.gradle
@@ -48,7 +48,7 @@
implementation(project(":benchmark:benchmark-common"))
implementation("androidx.profileinstaller:profileinstaller:1.0.3")
- implementation("androidx.tracing:tracing-ktx:1.0.0")
+ implementation(project(":tracing:tracing-ktx"))
implementation(libs.testCore)
implementation(libs.testUiautomator)
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/AndroidxTracingTraceTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/AndroidxTracingTraceTest.kt
new file mode 100644
index 0000000..16d883e
--- /dev/null
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/AndroidxTracingTraceTest.kt
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2021 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.benchmark.macro.perfetto
+
+import androidx.benchmark.macro.FileLinkingRule
+import androidx.benchmark.macro.Packages
+import androidx.benchmark.perfetto.PerfettoCapture
+import androidx.benchmark.perfetto.PerfettoHelper
+import androidx.benchmark.perfetto.PerfettoHelper.Companion.isAbiSupported
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import androidx.test.filters.SdkSuppress
+import androidx.tracing.Trace
+import androidx.tracing.trace
+import org.junit.After
+import org.junit.Assert.assertTrue
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import kotlin.test.assertEquals
+import kotlin.test.assertTrue
+
+/**
+ * Tests for androidx.tracing.Trace, which validate actual trace content
+ *
+ * These can't be defined in the androidx.tracing library, as Trace capture / validation APIs
+ * are only available to the benchmark group.
+ */
+@SdkSuppress(minSdkVersion = 23)
+@RunWith(AndroidJUnit4::class)
+class AndroidxTracingTraceTest {
+ @get:Rule
+ val linkRule = FileLinkingRule()
+
+ @Before
+ @After
+ fun cleanup() {
+ PerfettoHelper.stopAllPerfettoProcesses()
+ }
+
+ @LargeTest
+ @Test
+ fun captureAndValidateTrace() {
+ assumeTrue(isAbiSupported())
+
+ val traceFilePath = linkRule.createReportedTracePath(Packages.TEST)
+ val perfettoCapture = PerfettoCapture()
+
+ verifyTraceEnable(false)
+
+ perfettoCapture.start(listOf(Packages.TEST))
+
+ assertTrue(
+ Trace.isEnabled(),
+ "In-process tracing should be enabled immediately after trace capture is started"
+ )
+
+ repeat(20) {
+ "$PREFIX$it".also { label ->
+ // actual test content. This is done in the middle of the other sections
+ // to isolate it from trace truncation issues
+ if (it == 10) {
+ Trace.setCounter("${PREFIX}counter", 1)
+ Trace.beginSection("${PREFIX}beginSection")
+ Trace.beginAsyncSection("${PREFIX}beginAsyncSection", 9827)
+ Thread.sleep(50)
+ Trace.setCounter("${PREFIX}counter", 0)
+ Trace.endSection()
+ Trace.endAsyncSection("${PREFIX}beginAsyncSection", 9827)
+ }
+
+ // trace sections before and after actual test content, to look for problems in
+ // front/back trace truncation. If these sections are missing, it's most likely
+ // issues in trace capture
+ trace(label) { Thread.sleep(50) }
+ }
+ }
+
+ perfettoCapture.stop(traceFilePath)
+
+ val queryResult = PerfettoTraceProcessor.rawQuery(
+ absoluteTracePath = traceFilePath,
+ query = QUERY
+ )
+ val matchingSlices = Slice.parseListFromQueryResult(queryResult)
+ assertEquals(
+ List(10) { "$PREFIX$it" } +
+ listOf(
+ "${PREFIX}counter1.0",
+ "${PREFIX}beginSection",
+ "${PREFIX}beginAsyncSection",
+ "${PREFIX}counter0.0",
+ ) +
+ List(10) { "$PREFIX${it + 10}" },
+ matchingSlices.map { it.name }
+ )
+ matchingSlices
+ .forEach {
+ if (it.name.startsWith("${PREFIX}counter")) {
+ assertEquals(0L, it.dur) // counter has no length
+ } else {
+ assertTrue(it.dur > 30_000_000) // should be at least 30ms
+ }
+ }
+ }
+ companion object {
+ const val PREFIX = "AndroidxTracingTraceTest_"
+
+ const val QUERY = """
+ ------ select all relevant standard slices
+ SELECT
+ slice.name as name,
+ slice.ts as ts,
+ slice.dur as dur
+ FROM slice
+ INNER JOIN thread_track on slice.track_id = thread_track.id
+ INNER JOIN thread USING(utid)
+ INNER JOIN process USING(upid)
+ WHERE
+ slice.name LIKE "$PREFIX%" AND
+ process.name LIKE "androidx.benchmark.macro.test"
+ UNION
+ ------ add in async slices
+ SELECT
+ slice.name as name,
+ slice.ts as ts,
+ slice.dur as dur
+ FROM slice
+ INNER JOIN process_track on slice.track_id = process_track.id
+ INNER JOIN process USING(upid)
+ WHERE
+ slice.name LIKE "$PREFIX%" AND
+ process.name LIKE "androidx.benchmark.macro.test"
+ UNION
+ ------ add in the counter values, with value prepended to name
+ SELECT
+ counter_track.name || counter.value as name,
+ counter.ts as ts,
+ 0 as dur
+ FROM counter
+ INNER JOIN counter_track on counter.track_id = counter_track.id
+ WHERE
+ counter_track.name LIKE "${PREFIX}counter"
+ ------ order the whole thing by timestamp
+ ORDER BY
+ ts
+ """
+ }
+}
diff --git a/tracing/tracing/src/main/java/androidx/tracing/Trace.java b/tracing/tracing/src/main/java/androidx/tracing/Trace.java
index 0520f2e..03c6ead 100644
--- a/tracing/tracing/src/main/java/androidx/tracing/Trace.java
+++ b/tracing/tracing/src/main/java/androidx/tracing/Trace.java
@@ -16,7 +16,6 @@
package androidx.tracing;
-import android.annotation.SuppressLint;
import android.os.Build;
import android.util.Log;
@@ -55,12 +54,10 @@
*
* @return true if tracing is currently enabled, false otherwise
*/
- @SuppressLint("NewApi")
public static boolean isEnabled() {
if (Build.VERSION.SDK_INT >= 29) {
return TraceApi29Impl.isEnabled();
}
-
return isEnabledFallback();
}
@@ -103,16 +100,12 @@
* @param methodName The method name to appear in the trace.
* @param cookie Unique identifier for distinguishing simultaneous events
*/
- @SuppressLint("NewApi")
public static void beginAsyncSection(@NonNull String methodName, int cookie) {
- try {
- if (sAsyncTraceBeginMethod == null) {
- TraceApi29Impl.beginAsyncSection(methodName, cookie);
- return;
- }
- } catch (NoSuchMethodError | NoClassDefFoundError ignore) {
+ if (Build.VERSION.SDK_INT >= 29) {
+ TraceApi29Impl.beginAsyncSection(methodName, cookie);
+ } else {
+ beginAsyncSectionFallback(methodName, cookie);
}
- beginAsyncSectionFallback(methodName, cookie);
}
/**
@@ -123,16 +116,12 @@
* @param methodName The method name to appear in the trace.
* @param cookie Unique identifier for distinguishing simultaneous events
*/
- @SuppressLint("NewApi")
public static void endAsyncSection(@NonNull String methodName, int cookie) {
- try {
- if (sAsyncTraceEndMethod == null) {
- TraceApi29Impl.endAsyncSection(methodName, cookie);
- return;
- }
- } catch (NoSuchMethodError | NoClassDefFoundError ignore) {
+ if (Build.VERSION.SDK_INT >= 29) {
+ TraceApi29Impl.endAsyncSection(methodName, cookie);
+ } else {
+ endAsyncSectionFallback(methodName, cookie);
}
- endAsyncSectionFallback(methodName, cookie);
}
/**
@@ -141,16 +130,12 @@
* @param counterName The counter name to appear in the trace.
* @param counterValue The counter value.
*/
- @SuppressLint("NewApi")
public static void setCounter(@NonNull String counterName, int counterValue) {
- try {
- if (sTraceCounterMethod == null) {
- TraceApi29Impl.setCounter(counterName, counterValue);
- return;
- }
- } catch (NoSuchMethodError | NoClassDefFoundError ignore) {
+ if (Build.VERSION.SDK_INT >= 29) {
+ TraceApi29Impl.setCounter(counterName, counterValue);
+ } else {
+ setCounterFallback(counterName, counterValue);
}
- setCounterFallback(counterName, counterValue);
}
private static boolean isEnabledFallback() {