diff --git a/papa-dev/build.gradle.kts b/papa-dev/build.gradle.kts index 799c382..94da198 100644 --- a/papa-dev/build.gradle.kts +++ b/papa-dev/build.gradle.kts @@ -40,4 +40,5 @@ dependencies { compileOnly(Dependencies.Build.AndroidXAnnotation) implementation(project(":papa")) + implementation(Dependencies.AndroidXTracing) } diff --git a/papa-dev/src/main/AndroidManifest.xml b/papa-dev/src/main/AndroidManifest.xml index 1ae37c1..c738e10 100644 --- a/papa-dev/src/main/AndroidManifest.xml +++ b/papa-dev/src/main/AndroidManifest.xml @@ -2,18 +2,6 @@ - - - - - - - - - ` on API 29+, which indicate an intention for this build * to be a special build that you want to profile. - * - * You can force this to be true by calling [forceShellProfileable], which - * will enable app tracing even on non-shell-profileable builds. - * - * You can also trigger [forceShellProfileable] at runtime by sending a - * `papa.FORCE_SHELL_PROFILEABLE` broadcast. To support this you should add a - * dependency on the papa-dev artifact. */ @JvmStatic val isShellProfileable: Boolean @@ -48,30 +39,18 @@ object SafeTrace { * Whether we are currently tracing, which determines whether calls to * tracing functions will be forwarded to the Android tracing APIs. */ + @Deprecated("Use androidx.tracing.Trace.isEnabled() instead", ReplaceWith("Trace.isEnabled()", "androidx.tracing.Trace")) @JvmStatic val isCurrentlyTracing: Boolean get() = androidx.tracing.Trace.isEnabled() - @Deprecated("Use forceShellProfileable instead", ReplaceWith("forceShellProfileable()")) - @JvmStatic - fun forceTraceable() = forceShellProfileable() - - /** - * @see isShellProfileable - */ - @JvmStatic - fun forceShellProfileable() { - androidx.tracing.Trace.forceEnableAppTracing() - _isTraceable = true - SafeTraceMainThreadMessages.enableMainThreadMessageTracing() - } - @Suppress("NOTHING_TO_INLINE") private inline fun isShellProfileableInlined(): Boolean { // Prior to SafeTraceSetup.initDone we can't determine if the app is traceable or not, so we - // always return false, unless something called forceTraceable(). The first call after - // SafeTraceSetup.initDone becomes true will compute the actual value based on debuggable - // and profileable manifest flags, then cache it so that we don't need to recheck again. + // always return false. The first call after SafeTraceSetup.initDone + // becomes true will compute the actual value based on debuggable and + // profileable manifest flags, then cache it so that we don't need to + // recheck again. return _isTraceable ?: if (SafeTraceSetup.initDone) { val application = SafeTraceSetup.application @@ -93,17 +72,19 @@ object SafeTrace { * 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. */ + @Deprecated("Call androidx.tracing.Trace.beginSection instead", ReplaceWith("beginSection", "androidx.tracing.Trace.beginSection")) @JvmStatic fun beginSection(label: String) { - if (!isCurrentlyTracing) { + if (!androidx.tracing.Trace.isEnabled()) { return } androidx.tracing.Trace.beginSection(label.take(MAX_LABEL_LENGTH)) } + @Deprecated("Call androidx.tracing.Trace.beginSection instead", ReplaceWith("beginSection", "androidx.tracing.Trace.beginSection")) @JvmStatic inline fun beginSection(crossinline labelLambda: () -> String) { - if (!isCurrentlyTracing) { + if (!androidx.tracing.Trace.isEnabled()) { return } androidx.tracing.Trace.beginSection(labelLambda().take(MAX_LABEL_LENGTH)) @@ -113,8 +94,9 @@ object SafeTrace { * Begins and ends a section immediately. Useful for reporting information in the trace. */ @JvmStatic + @Deprecated("Call androidx.tracing.Trace.beginSection/endSection instead") fun logSection(label: String) { - if (!isCurrentlyTracing) { + if (!androidx.tracing.Trace.isEnabled()) { return } androidx.tracing.Trace.beginSection(label.take(MAX_LABEL_LENGTH)) @@ -124,9 +106,10 @@ object SafeTrace { /** * @see [logSection] */ + @Deprecated("Call androidx.tracing.Trace.beginSection/endSection instead") @JvmStatic inline fun logSection(crossinline labelLambda: () -> String) { - if (!isCurrentlyTracing) { + if (!androidx.tracing.Trace.isEnabled()) { return } val label = labelLambda().take(MAX_LABEL_LENGTH) @@ -141,9 +124,10 @@ object SafeTrace { * ensure that beginSection / endSection pairs are properly nested and called from the same * thread. */ + @Deprecated("Call androidx.tracing.Trace.endSection instead", ReplaceWith("endSection", "androidx.tracing.Trace.endSection")) @JvmStatic fun endSection() { - if (!isCurrentlyTracing) { + if (!androidx.tracing.Trace.isEnabled()) { return } androidx.tracing.Trace.endSection() @@ -152,11 +136,12 @@ object SafeTrace { /** * @see androidx.tracing.Trace.beginAsyncSection */ + @Deprecated("Call androidx.tracing.Trace.beginAsyncSection instead", ReplaceWith("beginAsyncSection", "androidx.tracing.Trace.beginAsyncSection")) @JvmStatic inline fun beginAsyncSection( crossinline labelCookiePairLambda: () -> Pair ) { - if (!isCurrentlyTracing) { + if (!androidx.tracing.Trace.isEnabled()) { return } val (label, cookie) = labelCookiePairLambda() @@ -167,12 +152,13 @@ object SafeTrace { * [cookie] defaults to 0 (cookie is used for async traces that overlap) * @see androidx.tracing.Trace.beginAsyncSection */ + @Deprecated("Call androidx.tracing.Trace.beginAsyncSection instead", ReplaceWith("beginAsyncSection", "androidx.tracing.Trace.beginAsyncSection")) @JvmStatic fun beginAsyncSection( label: String, cookie: Int = 0 ) { - if (!isCurrentlyTracing) { + if (!androidx.tracing.Trace.isEnabled()) { return } androidx.tracing.Trace.beginAsyncSection(label, cookie) @@ -182,12 +168,13 @@ object SafeTrace { * [cookie] defaults to 0 (cookie is used for async traces that overlap) * @see androidx.tracing.Trace.endAsyncSection */ + @Deprecated("Call androidx.tracing.Trace.endAsyncSection instead", ReplaceWith("endAsyncSection", "androidx.tracing.Trace.endAsyncSection")) @JvmStatic fun endAsyncSection( label: String, cookie: Int = 0 ) { - if (!isCurrentlyTracing) { + if (!androidx.tracing.Trace.isEnabled()) { return } androidx.tracing.Trace.endAsyncSection(label, cookie) @@ -196,11 +183,12 @@ object SafeTrace { /** * @see androidx.tracing.Trace.beginAsyncSection */ + @Deprecated("Call androidx.tracing.Trace.endAsyncSection instead", ReplaceWith("endAsyncSection", "androidx.tracing.Trace.endAsyncSection")) @JvmStatic inline fun endAsyncSection( crossinline labelCookiePairLambda: () -> Pair ) { - if (!isCurrentlyTracing) { + if (!androidx.tracing.Trace.isEnabled()) { return } val (label, cookie) = labelCookiePairLambda() diff --git a/papa-safetrace/src/main/java/papa/SafeTraceFunctions.kt b/papa-safetrace/src/main/java/papa/SafeTraceFunctions.kt index e30734c..2704cfb 100644 --- a/papa-safetrace/src/main/java/papa/SafeTraceFunctions.kt +++ b/papa-safetrace/src/main/java/papa/SafeTraceFunctions.kt @@ -8,6 +8,8 @@ import papa.SafeTrace.isTraceable * [label] a string producing lambda if the label is computed dynamically. If the label isn't * dynamic, use the [safeTrace] which directly takes a string instead. */ +@Deprecated("Call androidx.tracing.trace instead", ReplaceWith("trace", "androidx.tracing.trace")) +@Suppress("DEPRECATION") inline fun safeTrace( crossinline label: () -> String, crossinline block: () -> T @@ -26,6 +28,8 @@ inline fun safeTrace( /** * Allows tracing of a block of code */ +@Deprecated("Call androidx.tracing.trace instead", ReplaceWith("trace", "androidx.tracing.trace")) +@Suppress("DEPRECATION") inline fun safeTrace( label: String, crossinline block: () -> T diff --git a/papa-safetrace/src/main/java/papa/SafeTraceSetup.kt b/papa-safetrace/src/main/java/papa/SafeTraceSetup.kt index 65f76ff..7330bb6 100644 --- a/papa-safetrace/src/main/java/papa/SafeTraceSetup.kt +++ b/papa-safetrace/src/main/java/papa/SafeTraceSetup.kt @@ -13,6 +13,10 @@ object SafeTraceSetup { fun init(application: Application) { this.application = application + enableMainThreadMessageTracing() + } + + fun enableMainThreadMessageTracing() { SafeTraceMainThreadMessages.enableMainThreadMessageTracing() } diff --git a/papa-safetrace/src/main/java/papa/internal/SafeTraceMainThreadMessages.kt b/papa-safetrace/src/main/java/papa/internal/SafeTraceMainThreadMessages.kt index cc258ea..f1d091e 100644 --- a/papa-safetrace/src/main/java/papa/internal/SafeTraceMainThreadMessages.kt +++ b/papa-safetrace/src/main/java/papa/internal/SafeTraceMainThreadMessages.kt @@ -32,6 +32,7 @@ internal object SafeTraceMainThreadMessages { } } + @Suppress("DEPRECATION") private fun enableOnMainThread() { if (!enabled && SafeTrace.isShellProfileable && traceMainThreadMessages) { enabled = true diff --git a/papa/build.gradle.kts b/papa/build.gradle.kts index fbd0cbd..e79b16b 100644 --- a/papa/build.gradle.kts +++ b/papa/build.gradle.kts @@ -50,6 +50,7 @@ dependencies { implementation(Dependencies.Curtains) implementation(Dependencies.AndroidXCore) + implementation(Dependencies.AndroidXTracing) testImplementation(Dependencies.JUnit) testImplementation(Dependencies.Mockito) diff --git a/papa/src/main/java/papa/InteractionRuleClient.kt b/papa/src/main/java/papa/InteractionRuleClient.kt index 7adf2d9..0252b11 100644 --- a/papa/src/main/java/papa/InteractionRuleClient.kt +++ b/papa/src/main/java/papa/InteractionRuleClient.kt @@ -1,5 +1,6 @@ package papa +import androidx.tracing.Trace import papa.InteractionUpdated.CanceledOnEvent import papa.InteractionUpdated.CanceledOnRuleRemoved import papa.InteractionUpdated.CanceledOnTimeout @@ -119,18 +120,16 @@ private class InteractionEngine( * called with an unknown [Runnable]. */ private val cancelOnTimeout: Runnable = Runnable { - SafeTrace.logSection { - "PAPA-cancel:timeout" - } + Trace.beginSection("PAPA-cancel:timeout") + Trace.endSection() stopRunning() trace.endTrace() updateListener.onInteractionUpdate(CanceledOnTimeout(cancelTimeout, this)) } fun cancelOnRuleRemoved() { - SafeTrace.logSection { - "PAPA-cancel:ruleRemoved" - } + Trace.beginSection("PAPA-cancel:ruleRemoved") + Trace.endSection() stopRunning() trace.endTrace() updateListener.onInteractionUpdate(CanceledOnRuleRemoved(this)) @@ -153,9 +152,8 @@ private class InteractionEngine( override fun cancel(reason: String) { val sentEvent = eventInScope!! - SafeTrace.logSection { - "PAPA-cancel:${sentEvent.event}:$reason" - } + Trace.beginSection("PAPA-cancel:${sentEvent.event}:$reason") + Trace.endSection() stopRunning() trace.endTrace() updateListener.onInteractionUpdate(CanceledOnEvent(sentEvent, this, reason)) @@ -163,9 +161,8 @@ private class InteractionEngine( override fun finish(): FinishingInteraction { val sentEvent = eventInScope!! - SafeTrace.logSection { - "PAPA-finishInteraction:${sentEvent.event}" - } + Trace.beginSection("PAPA-finishInteraction:${sentEvent.event}") + Trace.endSection() stopRunning() finishingInteractions += this addRecordedEvent() @@ -188,9 +185,8 @@ private class InteractionEngine( override fun recordEvent() { val sentEvent = eventInScope!! - SafeTrace.logSection { - "PAPA-recordEvent:${sentEvent.event}" - } + Trace.beginSection("PAPA-recordEvent:${sentEvent.event}") + Trace.endSection() addRecordedEvent() updateListener.onInteractionUpdate(EventRecorded(sentEvent, this)) } @@ -230,9 +226,8 @@ private class InteractionEngine( trace: InteractionTrace, cancelTimeout: Duration ): RunningInteraction { - SafeTrace.logSection { - "PAPA-startInteraction:${sentEvent.event}" - } + Trace.beginSection("PAPA-startInteraction:${sentEvent.event}") + Trace.endSection() val runningInteraction = RealRunningInteraction( interactionTrigger = trigger, trace = trace, diff --git a/papa/src/main/java/papa/InteractionTrace.kt b/papa/src/main/java/papa/InteractionTrace.kt index ad97c02..995eb21 100644 --- a/papa/src/main/java/papa/InteractionTrace.kt +++ b/papa/src/main/java/papa/InteractionTrace.kt @@ -1,5 +1,7 @@ package papa +import androidx.tracing.Trace + fun interface InteractionTrace { fun endTrace() @@ -8,9 +10,9 @@ fun interface InteractionTrace { name: String ): InteractionTrace { val cookie = System.nanoTime().rem(Int.MAX_VALUE).toInt() - SafeTrace.beginAsyncSection(name, cookie) + Trace.beginAsyncSection(name, cookie) return InteractionTrace { - SafeTrace.endAsyncSection(name, cookie) + Trace.endAsyncSection(name, cookie) } } } diff --git a/papa/src/main/java/papa/internal/ApplicationHolder.kt b/papa/src/main/java/papa/internal/ApplicationHolder.kt index 0226f9d..3e7d347 100644 --- a/papa/src/main/java/papa/internal/ApplicationHolder.kt +++ b/papa/src/main/java/papa/internal/ApplicationHolder.kt @@ -1,9 +1,9 @@ package papa.internal import android.app.Application +import androidx.tracing.Trace import com.squareup.papa.R import papa.MainThreadMessageSpy -import papa.SafeTrace import papa.SafeTraceSetup /** @@ -21,7 +21,7 @@ internal object ApplicationHolder { this.application = application SafeTraceSetup.init(application) if (isForegroundImportance) { - SafeTrace.beginAsyncSection(Perfs.LAUNCH_TRACE_NAME) + Trace.beginAsyncSection(Perfs.LAUNCH_TRACE_NAME, 0) } val resources = application.resources if (resources.getBoolean(R.bool.papa_track_input_events)) { diff --git a/papa/src/main/java/papa/internal/InputTracker.kt b/papa/src/main/java/papa/internal/InputTracker.kt index 0b2831c..687f376 100644 --- a/papa/src/main/java/papa/internal/InputTracker.kt +++ b/papa/src/main/java/papa/internal/InputTracker.kt @@ -8,6 +8,8 @@ import android.view.MotionEvent import android.view.ViewConfiguration import android.view.ViewGroup import android.widget.AbsListView +import androidx.tracing.Trace +import androidx.tracing.trace import curtains.Curtains import curtains.KeyEventInterceptor import curtains.OnRootViewAddedListener @@ -19,9 +21,7 @@ import curtains.windowAttachCount import papa.InputEventTrigger import papa.InteractionTriggerWithPayload import papa.MainThreadTriggerStack -import papa.SafeTrace import papa.internal.FrozenFrameOnTouchDetector.findPressedView -import papa.safeTrace import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.nanoseconds @@ -46,7 +46,7 @@ internal object InputTracker { // the code that captured the event at time N. val actionUpTrigger = if (isActionUp) { val cookie = deliveryUptimeNanos.rem(Int.MAX_VALUE).toInt() - SafeTrace.beginAsyncSection(TAP_INTERACTION_SECTION, cookie) + Trace.beginAsyncSection(TAP_INTERACTION_SECTION, cookie) val eventUptime = motionEvent.eventTime.milliseconds // Event bugfix: if event time is after delivery time, use delivery time as trigger time. val triggerUptime = if (eventUptime > deliveryUptime) deliveryUptime else eventUptime @@ -55,7 +55,7 @@ internal object InputTracker { triggerUptime = triggerUptime, name = "tap", interactionTrace = { - SafeTrace.endAsyncSection(TAP_INTERACTION_SECTION, cookie) + Trace.endAsyncSection(TAP_INTERACTION_SECTION, cookie) }, payload = InputEventTrigger.createTrackingWhenFrameRendered( inputEventWindow = window, @@ -76,9 +76,7 @@ internal object InputTracker { handler.post(setEventForPostedClick) } - val dispatchState = safeTrace( - { MotionEvent.actionToString(motionEvent.action) } - ) { + val dispatchState = trace(MotionEvent.actionToString(motionEvent.action)) { if (actionUpTrigger != null) { // In case the action up is immediately triggering a click (e.g. Compose) MainThreadTriggerStack.triggeredBy( @@ -102,7 +100,7 @@ internal object InputTracker { } val dispatchEnd = SystemClock.uptimeMillis() - val viewPressedAfterDispatch = safeTrace("findPressedView()") { + val viewPressedAfterDispatch = trace("findPressedView()") { (window.decorView as? ViewGroup)?.findPressedView() } // AbsListView subclasses post clicks with a delay. @@ -128,7 +126,7 @@ internal object InputTracker { val deliveryUptimeNanos = System.nanoTime() val traceSectionName = keyEvent.traceSectionName val cookie = deliveryUptimeNanos.rem(Int.MAX_VALUE).toInt() - SafeTrace.beginAsyncSection(traceSectionName, cookie) + Trace.beginAsyncSection(traceSectionName, cookie) val deliveryUptime = deliveryUptimeNanos.nanoseconds val eventUptime = keyEvent.eventTime.milliseconds @@ -139,7 +137,7 @@ internal object InputTracker { triggerUptime = triggerUptime, name = "key ${keyEvent.name}", interactionTrace = { - SafeTrace.endAsyncSection(traceSectionName, cookie) + Trace.endAsyncSection(traceSectionName, cookie) }, payload = InputEventTrigger.createTrackingWhenFrameRendered( inputEventWindow = window, diff --git a/papa/src/main/java/papa/internal/LaunchTracker.kt b/papa/src/main/java/papa/internal/LaunchTracker.kt index 966c93e..3b6a2ba 100644 --- a/papa/src/main/java/papa/internal/LaunchTracker.kt +++ b/papa/src/main/java/papa/internal/LaunchTracker.kt @@ -2,10 +2,10 @@ package papa.internal import android.app.Activity import android.os.SystemClock +import androidx.tracing.Trace import papa.Choreographers import papa.Handlers import papa.OnFrameRenderedListener -import papa.SafeTrace import kotlin.time.Duration internal class LaunchTracker( @@ -58,7 +58,7 @@ internal class LaunchTracker( launchInProgress?.let { launch -> if (launch.isStale) { if (Perfs.isTracingLaunch) { - SafeTrace.endAsyncSection(Perfs.LAUNCH_TRACE_NAME) + Trace.endAsyncSection(Perfs.LAUNCH_TRACE_NAME, 0) Perfs.isTracingLaunch = false } launchInProgress = null @@ -76,7 +76,7 @@ internal class LaunchTracker( if (launchInProgress == null) { // Check to handle the cold start case where we're already tracing a launch. if (!Perfs.isTracingLaunch) { - SafeTrace.beginAsyncSection(Perfs.LAUNCH_TRACE_NAME) + Trace.beginAsyncSection(Perfs.LAUNCH_TRACE_NAME, 0) Perfs.isTracingLaunch = true } diff --git a/papa/src/main/java/papa/internal/Perfs.kt b/papa/src/main/java/papa/internal/Perfs.kt index 2958e4b..93dbc9c 100644 --- a/papa/src/main/java/papa/internal/Perfs.kt +++ b/papa/src/main/java/papa/internal/Perfs.kt @@ -11,6 +11,7 @@ import android.os.Looper import android.os.Process import android.os.StrictMode import android.os.SystemClock +import androidx.tracing.Trace import papa.AndroidComponentEvent import papa.AppLaunchType.COLD import papa.AppStart @@ -38,7 +39,6 @@ import papa.PreLaunchState.NO_PROCESS_FIRST_LAUNCH_AFTER_CLEAR_DATA import papa.PreLaunchState.NO_PROCESS_FIRST_LAUNCH_AFTER_INSTALL import papa.PreLaunchState.NO_PROCESS_FIRST_LAUNCH_AFTER_UPGRADE import papa.PreLaunchState.PROCESS_WAS_LAUNCHING_IN_BACKGROUND -import papa.SafeTrace import papa.internal.AppUpdateDetector.Companion.trackAppUpgrade import papa.internal.LaunchTracker.Launch import papa.internal.LaunchedActivityStartingTransition.CREATED_NO_STATE @@ -270,7 +270,7 @@ internal object Perfs { initCalledRealtimeMillis ) if (isTracingLaunch) { - SafeTrace.endAsyncSection(LAUNCH_TRACE_NAME) + Trace.endAsyncSection(LAUNCH_TRACE_NAME, 0) isTracingLaunch = false } PapaEventListener.sendEvent(