Separate tracing to its own module.

* Startup & Benchmark can now depend on this artifact rather than having
  to take a dependency on core. This also fixes the naming problem of these
  methods being titled "Compat", when vast majority of developer calls
  will go through the AndroidX lib, vs the platform.

Test: Added a unit test for the Kotlin extension.
Change-Id: I39d57ef768446106a698427b11760ba846815de9
diff --git a/buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt b/buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt
index 49783c6..a71eb41 100644
--- a/buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt
@@ -96,6 +96,7 @@
         LibraryVersions.SWIPEREFRESHLAYOUT)
     val TESTSCREENSHOT = LibraryGroup("androidx.test.screenshot", LibraryVersions.TESTSCREENSHOT)
     val TEXTCLASSIFIER = LibraryGroup("androidx.textclassifier", LibraryVersions.TEXTCLASSIFIER)
+    val TRACING = LibraryGroup("androidx.tracing", LibraryVersions.TRACING)
     val TRANSITION = LibraryGroup("androidx.transition", LibraryVersions.TRANSITION)
     val TVPROVIDER = LibraryGroup("androidx.tvprovider", LibraryVersions.TVPROVIDER)
     val UI = LibraryGroup("androidx.ui", null)
diff --git a/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt b/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
index d156fae..89e4da1 100644
--- a/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
@@ -104,6 +104,7 @@
     val SWIPEREFRESHLAYOUT = Version("1.1.0-beta02")
     val TESTSCREENSHOT = Version("1.0.0-alpha01")
     val TEXTCLASSIFIER = Version("1.0.0-alpha03")
+    val TRACING = Version("1.0.0-alpha01")
     val TRANSITION = Version("1.4.0-alpha01")
     val TVPROVIDER = Version("1.1.0-alpha01")
     val UI = Version("0.1.0-dev07")
diff --git a/settings.gradle b/settings.gradle
index 8214feb..7ea9059 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -273,6 +273,8 @@
 includeProject(":test-screenshot-proto", "test/screenshot/proto")
 includeProject(":textclassifier:textclassifier", "textclassifier/textclassifier")
 includeProject(":textclassifier:integration-tests:testapp", "textclassifier/integration-tests/testapp")
+includeProject(":tracing:tracing", "tracing/tracing")
+includeProject(":tracing:tracing-ktx", "tracing/tracing-ktx")
 includeProject(":transition:transition", "transition/transition")
 includeProject(":transition:transition-ktx", "transition/transition-ktx")
 includeProject(":tvprovider:tvprovider", "tv-provider/tv-provider")
diff --git a/tracing/tracing-ktx/api/1.0.0-alpha01.txt b/tracing/tracing-ktx/api/1.0.0-alpha01.txt
new file mode 100644
index 0000000..c72f21f
--- /dev/null
+++ b/tracing/tracing-ktx/api/1.0.0-alpha01.txt
@@ -0,0 +1,10 @@
+// Signature format: 3.0
+package androidx.tracing {
+
+  public final class TraceKt {
+    method public static inline <T> T! trace(String label, kotlin.jvm.functions.Function0<? extends T> block);
+    method public static inline <T> T! trace(kotlin.jvm.functions.Function0<java.lang.String> label, kotlin.jvm.functions.Function0<? extends T> block);
+  }
+
+}
+
diff --git a/tracing/tracing-ktx/api/current.txt b/tracing/tracing-ktx/api/current.txt
new file mode 100644
index 0000000..c72f21f
--- /dev/null
+++ b/tracing/tracing-ktx/api/current.txt
@@ -0,0 +1,10 @@
+// Signature format: 3.0
+package androidx.tracing {
+
+  public final class TraceKt {
+    method public static inline <T> T! trace(String label, kotlin.jvm.functions.Function0<? extends T> block);
+    method public static inline <T> T! trace(kotlin.jvm.functions.Function0<java.lang.String> label, kotlin.jvm.functions.Function0<? extends T> block);
+  }
+
+}
+
diff --git a/tracing/tracing-ktx/api/public_plus_experimental_1.0.0-alpha01.txt b/tracing/tracing-ktx/api/public_plus_experimental_1.0.0-alpha01.txt
new file mode 100644
index 0000000..c72f21f
--- /dev/null
+++ b/tracing/tracing-ktx/api/public_plus_experimental_1.0.0-alpha01.txt
@@ -0,0 +1,10 @@
+// Signature format: 3.0
+package androidx.tracing {
+
+  public final class TraceKt {
+    method public static inline <T> T! trace(String label, kotlin.jvm.functions.Function0<? extends T> block);
+    method public static inline <T> T! trace(kotlin.jvm.functions.Function0<java.lang.String> label, kotlin.jvm.functions.Function0<? extends T> block);
+  }
+
+}
+
diff --git a/tracing/tracing-ktx/api/public_plus_experimental_current.txt b/tracing/tracing-ktx/api/public_plus_experimental_current.txt
new file mode 100644
index 0000000..c72f21f
--- /dev/null
+++ b/tracing/tracing-ktx/api/public_plus_experimental_current.txt
@@ -0,0 +1,10 @@
+// Signature format: 3.0
+package androidx.tracing {
+
+  public final class TraceKt {
+    method public static inline <T> T! trace(String label, kotlin.jvm.functions.Function0<? extends T> block);
+    method public static inline <T> T! trace(kotlin.jvm.functions.Function0<java.lang.String> label, kotlin.jvm.functions.Function0<? extends T> block);
+  }
+
+}
+
diff --git a/tracing/tracing-ktx/api/res-1.0.0-alpha01.txt b/tracing/tracing-ktx/api/res-1.0.0-alpha01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tracing/tracing-ktx/api/res-1.0.0-alpha01.txt
diff --git a/tracing/tracing-ktx/api/restricted_1.0.0-alpha01.txt b/tracing/tracing-ktx/api/restricted_1.0.0-alpha01.txt
new file mode 100644
index 0000000..c72f21f
--- /dev/null
+++ b/tracing/tracing-ktx/api/restricted_1.0.0-alpha01.txt
@@ -0,0 +1,10 @@
+// Signature format: 3.0
+package androidx.tracing {
+
+  public final class TraceKt {
+    method public static inline <T> T! trace(String label, kotlin.jvm.functions.Function0<? extends T> block);
+    method public static inline <T> T! trace(kotlin.jvm.functions.Function0<java.lang.String> label, kotlin.jvm.functions.Function0<? extends T> block);
+  }
+
+}
+
diff --git a/tracing/tracing-ktx/api/restricted_current.txt b/tracing/tracing-ktx/api/restricted_current.txt
new file mode 100644
index 0000000..c72f21f
--- /dev/null
+++ b/tracing/tracing-ktx/api/restricted_current.txt
@@ -0,0 +1,10 @@
+// Signature format: 3.0
+package androidx.tracing {
+
+  public final class TraceKt {
+    method public static inline <T> T! trace(String label, kotlin.jvm.functions.Function0<? extends T> block);
+    method public static inline <T> T! trace(kotlin.jvm.functions.Function0<java.lang.String> label, kotlin.jvm.functions.Function0<? extends T> block);
+  }
+
+}
+
diff --git a/tracing/tracing-ktx/build.gradle b/tracing/tracing-ktx/build.gradle
new file mode 100644
index 0000000..cf75ad4
--- /dev/null
+++ b/tracing/tracing-ktx/build.gradle
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 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.
+ */
+
+
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.AndroidXExtension
+
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.Publish
+
+plugins {
+    id("AndroidXPlugin")
+    id("com.android.library")
+    id("kotlin-android")
+}
+
+android {
+    buildTypes {
+        debug {
+            // Breaks Kotlin compiler
+            testCoverageEnabled = false
+        }
+    }
+}
+
+dependencies {
+    api project(':tracing:tracing')
+    api(KOTLIN_STDLIB)
+
+    androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
+    androidTestImplementation(ANDROIDX_TEST_CORE)
+    androidTestImplementation(ANDROIDX_TEST_RUNNER)
+    testImplementation(JUNIT)
+}
+
+androidx {
+    name = "Android Tracing Runtime Kotlin Extensions"
+    publish = Publish.SNAPSHOT_AND_RELEASE
+    mavenGroup = LibraryGroups.TRACING
+    inceptionYear = "2020"
+    description = "Android Tracing"
+    url = AndroidXExtension.ARCHITECTURE_URL
+}
diff --git a/tracing/tracing-ktx/src/androidTest/java/androidx/tracing/TraceTestKt.kt b/tracing/tracing-ktx/src/androidTest/java/androidx/tracing/TraceTestKt.kt
new file mode 100644
index 0000000..269783e
--- /dev/null
+++ b/tracing/tracing-ktx/src/androidTest/java/androidx/tracing/TraceTestKt.kt
@@ -0,0 +1,35 @@
+/*
+ * 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.tracing
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class TraceTestKt {
+    @Test
+    fun traceTest() {
+        val x = trace({ "Test" }) {
+            10
+        }
+        assertEquals(10, x)
+    }
+}
diff --git a/tracing/tracing-ktx/src/main/AndroidManifest.xml b/tracing/tracing-ktx/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..976de72
--- /dev/null
+++ b/tracing/tracing-ktx/src/main/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<!--
+  ~ Copyright (C) 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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="androidx.tracing">
+
+</manifest>
diff --git a/tracing/tracing-ktx/src/main/java/androidx/tracing/Trace.kt b/tracing/tracing-ktx/src/main/java/androidx/tracing/Trace.kt
new file mode 100644
index 0000000..7b2c558
--- /dev/null
+++ b/tracing/tracing-ktx/src/main/java/androidx/tracing/Trace.kt
@@ -0,0 +1,53 @@
+/*
+ * 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.tracing
+
+/**
+ * Wrap the specified [block] in calls to [Trace.beginSection] (with the supplied [label])
+ * and [Trace.endSection].
+ *
+ * @param label A name of the code section to appear in the trace. This may
+ * be at most 127 Unicode code units long.
+ * @param block A block of code which is being traced.
+ */
+inline fun <T> trace(label: String, crossinline block: () -> T): T {
+    try {
+        Trace.beginSection(label)
+        return block()
+    } finally {
+        Trace.endSection()
+    }
+}
+
+/**
+ * Wrap the specified [block] in calls to [Trace.beginSection] (with the supplied [label] producer)
+ * and [Trace.endSection].
+ *
+ * @param label Produces a name of the code section to appear in the trace. This may
+ * be at most 127 Unicode code units long.
+ * @param block A block of code which is being traced.
+ */
+inline fun <T> trace(crossinline label: () -> String, crossinline block: () -> T): T {
+    try {
+        if (Trace.isEnabled()) {
+            Trace.beginSection(label())
+        }
+        return block()
+    } finally {
+        Trace.endSection()
+    }
+}
diff --git a/tracing/tracing/api/1.0.0-alpha01.txt b/tracing/tracing/api/1.0.0-alpha01.txt
new file mode 100644
index 0000000..4616fa4
--- /dev/null
+++ b/tracing/tracing/api/1.0.0-alpha01.txt
@@ -0,0 +1,14 @@
+// Signature format: 3.0
+package androidx.tracing {
+
+  public final class Trace {
+    method public static void beginAsyncSection(String, int);
+    method public static void beginSection(String);
+    method public static void endAsyncSection(String, int);
+    method public static void endSection();
+    method public static boolean isEnabled();
+    method public static void setCounter(String, int);
+  }
+
+}
+
diff --git a/tracing/tracing/api/current.txt b/tracing/tracing/api/current.txt
new file mode 100644
index 0000000..4616fa4
--- /dev/null
+++ b/tracing/tracing/api/current.txt
@@ -0,0 +1,14 @@
+// Signature format: 3.0
+package androidx.tracing {
+
+  public final class Trace {
+    method public static void beginAsyncSection(String, int);
+    method public static void beginSection(String);
+    method public static void endAsyncSection(String, int);
+    method public static void endSection();
+    method public static boolean isEnabled();
+    method public static void setCounter(String, int);
+  }
+
+}
+
diff --git a/tracing/tracing/api/public_plus_experimental_1.0.0-alpha01.txt b/tracing/tracing/api/public_plus_experimental_1.0.0-alpha01.txt
new file mode 100644
index 0000000..4616fa4
--- /dev/null
+++ b/tracing/tracing/api/public_plus_experimental_1.0.0-alpha01.txt
@@ -0,0 +1,14 @@
+// Signature format: 3.0
+package androidx.tracing {
+
+  public final class Trace {
+    method public static void beginAsyncSection(String, int);
+    method public static void beginSection(String);
+    method public static void endAsyncSection(String, int);
+    method public static void endSection();
+    method public static boolean isEnabled();
+    method public static void setCounter(String, int);
+  }
+
+}
+
diff --git a/tracing/tracing/api/public_plus_experimental_current.txt b/tracing/tracing/api/public_plus_experimental_current.txt
new file mode 100644
index 0000000..4616fa4
--- /dev/null
+++ b/tracing/tracing/api/public_plus_experimental_current.txt
@@ -0,0 +1,14 @@
+// Signature format: 3.0
+package androidx.tracing {
+
+  public final class Trace {
+    method public static void beginAsyncSection(String, int);
+    method public static void beginSection(String);
+    method public static void endAsyncSection(String, int);
+    method public static void endSection();
+    method public static boolean isEnabled();
+    method public static void setCounter(String, int);
+  }
+
+}
+
diff --git a/tracing/tracing/api/res-1.0.0-alpha01.txt b/tracing/tracing/api/res-1.0.0-alpha01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tracing/tracing/api/res-1.0.0-alpha01.txt
diff --git a/tracing/tracing/api/restricted_1.0.0-alpha01.txt b/tracing/tracing/api/restricted_1.0.0-alpha01.txt
new file mode 100644
index 0000000..4616fa4
--- /dev/null
+++ b/tracing/tracing/api/restricted_1.0.0-alpha01.txt
@@ -0,0 +1,14 @@
+// Signature format: 3.0
+package androidx.tracing {
+
+  public final class Trace {
+    method public static void beginAsyncSection(String, int);
+    method public static void beginSection(String);
+    method public static void endAsyncSection(String, int);
+    method public static void endSection();
+    method public static boolean isEnabled();
+    method public static void setCounter(String, int);
+  }
+
+}
+
diff --git a/tracing/tracing/api/restricted_current.txt b/tracing/tracing/api/restricted_current.txt
new file mode 100644
index 0000000..4616fa4
--- /dev/null
+++ b/tracing/tracing/api/restricted_current.txt
@@ -0,0 +1,14 @@
+// Signature format: 3.0
+package androidx.tracing {
+
+  public final class Trace {
+    method public static void beginAsyncSection(String, int);
+    method public static void beginSection(String);
+    method public static void endAsyncSection(String, int);
+    method public static void endSection();
+    method public static boolean isEnabled();
+    method public static void setCounter(String, int);
+  }
+
+}
+
diff --git a/tracing/tracing/build.gradle b/tracing/tracing/build.gradle
new file mode 100644
index 0000000..9381fec
--- /dev/null
+++ b/tracing/tracing/build.gradle
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 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.
+ */
+
+
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.AndroidXExtension
+
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.Publish
+
+plugins {
+    id("AndroidXPlugin")
+    id("com.android.library")
+    id("kotlin-android")
+}
+
+android {
+    buildTypes {
+        debug {
+            // Breaks Kotlin compiler
+            testCoverageEnabled = false
+        }
+    }
+}
+
+dependencies {
+    implementation("androidx.annotation:annotation:1.1.0")
+    androidTestImplementation(KOTLIN_STDLIB)
+    androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
+    androidTestImplementation(ANDROIDX_TEST_CORE)
+    androidTestImplementation(ANDROIDX_TEST_RUNNER)
+    testImplementation(JUNIT)
+}
+
+androidx {
+    name = "Android Tracing"
+    publish = Publish.SNAPSHOT_AND_RELEASE
+    mavenGroup = LibraryGroups.TRACING
+    inceptionYear = "2020"
+    description = "Android Tracing"
+    url = AndroidXExtension.ARCHITECTURE_URL
+}
diff --git a/tracing/tracing/src/androidTest/java/androidx/tracing/TraceTest.java b/tracing/tracing/src/androidTest/java/androidx/tracing/TraceTest.java
new file mode 100644
index 0000000..1ac1834
--- /dev/null
+++ b/tracing/tracing/src/androidTest/java/androidx/tracing/TraceTest.java
@@ -0,0 +1,171 @@
+/*
+ * 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.tracing;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.TestCase.assertTrue;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import android.app.UiAutomation;
+import android.os.Build;
+import android.os.ParcelFileDescriptor;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.SdkSuppress;
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+@LargeTest
+@SdkSuppress(minSdkVersion = 21) // Required for UiAutomation#executeShellCommand()
+public final class TraceTest {
+
+    private static final int TRACE_BUFFER_SIZE = 8192;
+    private ByteArrayOutputStream mByteArrayOutputStream;
+
+    @Before
+    public void setUp() {
+        mByteArrayOutputStream = new ByteArrayOutputStream();
+    }
+
+    @After
+    public void stopAtrace() throws IOException {
+        // Since API 23, 'async_stop' will work. On lower API levels it was broken (see aosp/157142)
+        if (Build.VERSION.SDK_INT >= 23) {
+            executeCommand("atrace --async_stop");
+        } else {
+            // Ensure tracing is not currently running by performing a short synchronous trace.
+            executeCommand("atrace -t 0");
+        }
+    }
+
+    @Test
+    public void beginAndEndSection() throws IOException {
+        startTrace();
+        Trace.beginSection("beginAndEndSection");
+        Trace.endSection();
+        dumpTrace();
+
+        assertTraceContains("tracing_mark_write:\\ B\\|.*\\|beginAndEndSection");
+        assertTraceContains("tracing_mark_write:\\ E");
+    }
+
+    @Test
+    public void beginAndEndSectionAsync() throws IOException {
+        startTrace();
+        Trace.beginAsyncSection("beginAndEndSectionAsync", /*cookie=*/5099);
+        Trace.endAsyncSection("beginAndEndSectionAsync", /*cookie=*/5099);
+        dumpTrace();
+
+        assertTraceContains("tracing_mark_write:\\ S\\|.*\\|beginAndEndSectionAsync\\|5099");
+        assertTraceContains("tracing_mark_write:\\ F\\|.*\\|beginAndEndSectionAsync\\|5099");
+    }
+
+    @Test
+    public void setCounter() throws IOException {
+        startTrace();
+        Trace.setCounter("counterName", 42);
+        Trace.setCounter("counterName", 47);
+        Trace.setCounter("counterName", 9787);
+        dumpTrace();
+
+        assertTraceContains("tracing_mark_write:\\ C\\|.*\\|counterName\\|42");
+        assertTraceContains("tracing_mark_write:\\ C\\|.*\\|counterName\\|47");
+        assertTraceContains("tracing_mark_write:\\ C\\|.*\\|counterName\\|9787");
+    }
+
+    @Test
+    public void isEnabledDuringTrace() throws IOException {
+        startTrace();
+        boolean enabled = Trace.isEnabled();
+        dumpTrace();
+        assertTrue(enabled);
+    }
+
+    @SmallTest
+    @Test
+    public void isNotEnabledWhenNotTracing() {
+        assertFalse(Trace.isEnabled());
+    }
+
+    private void startTrace() throws IOException {
+        String processName =
+                ApplicationProvider.getApplicationContext().getApplicationInfo().processName;
+
+        // Write the "async_start" status to the byte array to ensure atrace has fully started
+        // before issuing any trace commands. This will also capture any errors that occur during
+        // start so they can be added to the assertion error's message.
+        executeCommand(
+                String.format("atrace --async_start -b %d -a %s", TRACE_BUFFER_SIZE, processName));
+    }
+
+    private void dumpTrace() throws IOException {
+        // On older versions of atrace, the -b option is required when dumping the trace so the
+        // trace buffer doesn't get cleared before being dumped.
+        executeCommand(
+                String.format("atrace --async_dump -b %d", TRACE_BUFFER_SIZE),
+                mByteArrayOutputStream);
+    }
+
+    private static void executeCommand(@NonNull String command) throws IOException {
+        executeCommand(command, null);
+    }
+
+    private static void executeCommand(@NonNull String command,
+            @Nullable ByteArrayOutputStream outputStream) throws IOException {
+        UiAutomation automation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+
+        try (ParcelFileDescriptor pfDescriptor = automation.executeShellCommand(command);
+             ParcelFileDescriptor.AutoCloseInputStream inputStream =
+                     new ParcelFileDescriptor.AutoCloseInputStream(
+                             pfDescriptor)) {
+            byte[] buffer = new byte[1024];
+
+            int length;
+            while ((length = inputStream.read(buffer)) >= 0) {
+                if (outputStream != null) {
+                    outputStream.write(buffer, 0, length);
+                }
+            }
+        }
+    }
+
+    private void assertTraceContains(@NonNull String contentRegex) {
+        String traceString = new String(mByteArrayOutputStream.toByteArray(), UTF_8);
+
+        Pattern pattern = Pattern.compile(contentRegex);
+        Matcher matcher = pattern.matcher(traceString);
+
+        if (!matcher.find()) {
+            throw new AssertionError(
+                    String.format("Trace does not contain requested regex: %s\n%s", contentRegex,
+                            traceString));
+        }
+    }
+}
diff --git a/tracing/tracing/src/main/AndroidManifest.xml b/tracing/tracing/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..976de72
--- /dev/null
+++ b/tracing/tracing/src/main/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<!--
+  ~ Copyright (C) 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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="androidx.tracing">
+
+</manifest>
diff --git a/tracing/tracing/src/main/java/androidx/tracing/Trace.java b/tracing/tracing/src/main/java/androidx/tracing/Trace.java
new file mode 100644
index 0000000..aa2c7e5
--- /dev/null
+++ b/tracing/tracing/src/main/java/androidx/tracing/Trace.java
@@ -0,0 +1,183 @@
+/*
+ * 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.tracing;
+
+import android.os.Build;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+/**
+ * Writes trace events to the system trace buffer.  These trace events can be
+ * collected and visualized using the Systrace tool.
+ *
+ * <p>This tracing mechanism is independent of the method tracing mechanism
+ * offered by {@link android.os.Debug#startMethodTracing}.  In particular, it enables
+ * tracing of events that occur across multiple processes.
+ * <p>For information about using the Systrace tool, read <a
+ * href="{@docRoot}studio/profile/systrace/">Overview of system tracing</a>.
+ */
+public final class Trace {
+
+    private static final String TAG = "Trace";
+
+    private static long sTraceTagApp;
+    private static Method sIsTagEnabledMethod;
+    private static Method sAsyncTraceBeginMethod;
+    private static Method sAsyncTraceEndMethod;
+    private static Method sTraceCounterMethod;
+
+    static {
+        if (Build.VERSION.SDK_INT >= 18 && Build.VERSION.SDK_INT < 29) {
+            try {
+                Field traceTagAppField = android.os.Trace.class.getField("TRACE_TAG_APP");
+                sTraceTagApp = traceTagAppField.getLong(null);
+
+                sIsTagEnabledMethod = android.os.Trace.class.getMethod("isTagEnabled", long.class);
+                sAsyncTraceBeginMethod = android.os.Trace.class.getMethod("asyncTraceBegin",
+                        long.class,
+                        String.class, int.class);
+                sAsyncTraceEndMethod = android.os.Trace.class.getMethod("asyncTraceEnd", long.class,
+                        String.class, int.class);
+                sTraceCounterMethod = android.os.Trace.class.getMethod("traceCounter", long.class,
+                        String.class, int.class);
+            } catch (Exception e) {
+                Log.i(TAG, "Unable to initialize via reflection.", e);
+            }
+        }
+    }
+
+    /**
+     * Checks whether or not tracing is currently enabled. This is useful to avoid intermediate
+     * string creation for trace sections that require formatting. It is not necessary
+     * to guard all Trace method calls as they internally already check this. However it is
+     * recommended to use this to prevent creating any temporary objects that would then be
+     * passed to those methods to reduce runtime cost when tracing isn't enabled.
+     *
+     * @return true if tracing is currently enabled, false otherwise
+     */
+    public static boolean isEnabled() {
+        if (Build.VERSION.SDK_INT >= 29) {
+            return android.os.Trace.isEnabled();
+        } else if (Build.VERSION.SDK_INT >= 18) {
+            try {
+                return (boolean) sIsTagEnabledMethod.invoke(null, sTraceTagApp);
+            } catch (Exception e) {
+                Log.v(TAG, "Unable to invoke isTagEnabled() via reflection.");
+            }
+        }
+
+        // Never enabled on < API 18
+        return false;
+    }
+
+    /**
+     * Writes a trace message to indicate that a given section of code has begun. This call must
+     * be followed by a corresponding call to {@link #endSection()} on the same thread.
+     *
+     * <p class="note"> At this time the vertical bar character '|', newline character '\n', and
+     * null character '\0' are used internally by the tracing mechanism.  If sectionName contains
+     * these characters they will be replaced with a space character in the trace.
+     *
+     * @param label The name of the code section to appear in the trace.  This may be at
+     * most 127 Unicode code units long.
+     */
+    public static void beginSection(@NonNull String label) {
+        if (Build.VERSION.SDK_INT >= 18) {
+            android.os.Trace.beginSection(label);
+        }
+    }
+
+    /**
+     * Writes a trace message to indicate that a given section of code has ended. This call must
+     * be preceded by a corresponding call to {@link #beginSection(String)}. Calling this method
+     * will mark the end of the most recently begun section of code, so care must be taken to
+     * ensure that beginSection / endSection pairs are properly nested and called from the same
+     * thread.
+     */
+    public static void endSection() {
+        if (Build.VERSION.SDK_INT >= 18) {
+            android.os.Trace.endSection();
+        }
+    }
+
+    /**
+     * Writes a trace message to indicate that a given section of code has
+     * begun. Must be followed by a call to {@link #endAsyncSection(String, int)} with the same
+     * methodName and cookie. Unlike {@link #beginSection(String)} and {@link #endSection()},
+     * asynchronous events do not need to be nested. The name and cookie used to
+     * begin an event must be used to end it.
+     *
+     * @param methodName The method name to appear in the trace.
+     * @param cookie     Unique identifier for distinguishing simultaneous events
+     */
+    public static void beginAsyncSection(@NonNull String methodName, int cookie) {
+        if (Build.VERSION.SDK_INT >= 29) {
+            android.os.Trace.beginAsyncSection(methodName, cookie);
+        } else if (Build.VERSION.SDK_INT >= 18) {
+            try {
+                sAsyncTraceBeginMethod.invoke(null, sTraceTagApp, methodName, cookie);
+            } catch (Exception e) {
+                Log.v(TAG, "Unable to invoke asyncTraceBegin() via reflection.");
+            }
+        }
+    }
+
+    /**
+     * Writes a trace message to indicate that the current method has ended.
+     * Must be called exactly once for each call to {@link #beginAsyncSection(String, int)}
+     * using the same name and cookie.
+     *
+     * @param methodName The method name to appear in the trace.
+     * @param cookie     Unique identifier for distinguishing simultaneous events
+     */
+    public static void endAsyncSection(@NonNull String methodName, int cookie) {
+        if (Build.VERSION.SDK_INT >= 29) {
+            android.os.Trace.endAsyncSection(methodName, cookie);
+        } else if (Build.VERSION.SDK_INT >= 18) {
+            try {
+                sAsyncTraceEndMethod.invoke(null, sTraceTagApp, methodName, cookie);
+            } catch (Exception e) {
+                Log.v(TAG, "Unable to invoke endAsyncSection() via reflection.");
+            }
+        }
+    }
+
+
+    /**
+     * Writes trace message to indicate the value of a given counter.
+     *
+     * @param counterName  The counter name to appear in the trace.
+     * @param counterValue The counter value.
+     */
+    public static void setCounter(@NonNull String counterName, int counterValue) {
+        if (Build.VERSION.SDK_INT >= 29) {
+            android.os.Trace.setCounter(counterName, counterValue);
+        } else if (Build.VERSION.SDK_INT >= 18) {
+            try {
+                sTraceCounterMethod.invoke(null, sTraceTagApp, counterName, counterValue);
+            } catch (Exception e) {
+                Log.v(TAG, "Unable to invoke traceCounter() via reflection.");
+            }
+        }
+    }
+
+    private Trace() {}
+}