Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,6 @@ fun createActivityLoadEventEmitter(
*/
fun traceInstanceId(activity: Activity): Int = activity.hashCode()

/**
* Determine if the current instance of the app will fire render events
*
* Disabled temporarily as we figure out how it interacts with Compose navigation
*/
@Suppress("FunctionOnlyReturningConstant", "UNUSED_PARAMETER")
fun hasRenderEvent(versionChecker: VersionChecker): Boolean = false

/**
* Determine if the current instance of the app will pre and post lifecycle events
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.app.Application.ActivityLifecycleCallbacks
import io.embrace.android.embracesdk.internal.arch.schema.EmbType
import io.embrace.android.embracesdk.internal.spans.PersistableEmbraceSpan
import io.embrace.android.embracesdk.internal.spans.SpanService
import io.embrace.android.embracesdk.internal.ui.hasRenderEvent
import io.embrace.android.embracesdk.internal.utils.VersionChecker
import io.embrace.android.embracesdk.spans.EmbraceSpanEvent
import io.embrace.android.embracesdk.spans.ErrorCode
Expand Down Expand Up @@ -40,9 +41,9 @@ import java.util.concurrent.atomic.AtomicReference
*
* The end for both [UiLoadType.COLD] and [UiLoadType.HOT]:
*
* - Android 10+, when the Activity's first UI frame finishes rendering and is delivered to the screen
* - Android 6+, when the Activity's first UI frame finishes rendering and is delivered to the screen, as best as we can determine
*
* - Android 9 and lower, when [ActivityLifecycleCallbacks.onActivityResumed] is fired.
* - Android 5, when [ActivityLifecycleCallbacks.onActivityResumed] is fired.
*/
class UiLoadTraceEmitter(
private val spanService: SpanService,
Expand All @@ -51,7 +52,7 @@ class UiLoadTraceEmitter(

private val activeTraces: MutableMap<Int, UiLoadTrace> = ConcurrentHashMap()
private var currentInstance: AtomicReference<UiInstance?> = AtomicReference()
private val hasRenderEvent = hasRenderEvent(versionChecker)
private val trackRender = hasRenderEvent(versionChecker)
private val hasPrePostEvents = hasPrePostEvents(versionChecker)

override fun create(instanceId: Int, activityName: String, timestampMs: Long, manualEnd: Boolean) {
Expand Down Expand Up @@ -113,7 +114,7 @@ class UiLoadTraceEmitter(
instanceId = instanceId,
timestampMs = timestampMs,
)
} else if (!hasRenderEvent && traceCompleteTrigger(instanceId) == TraceCompleteTrigger.MANUAL) {
} else if (!trackRender && traceCompleteTrigger(instanceId) == TraceCompleteTrigger.MANUAL) {
startChildSpan(
instanceId = instanceId,
timestampMs = timestampMs,
Expand All @@ -136,7 +137,7 @@ class UiLoadTraceEmitter(
instanceId = instanceId,
timestampMs = timestampMs,
)
} else if (!hasRenderEvent && endType == TraceCompleteTrigger.MANUAL) {
} else if (!trackRender && endType == TraceCompleteTrigger.MANUAL) {
startChildSpan(
instanceId = instanceId,
timestampMs = timestampMs,
Expand All @@ -146,7 +147,7 @@ class UiLoadTraceEmitter(
}

override fun render(instanceId: Int, timestampMs: Long) {
if (hasRenderEvent) {
if (trackRender) {
startChildSpan(
instanceId = instanceId,
timestampMs = timestampMs,
Expand All @@ -156,7 +157,7 @@ class UiLoadTraceEmitter(
}

override fun renderEnd(instanceId: Int, timestampMs: Long) {
if (hasRenderEvent) {
if (trackRender) {
endChildSpan(
instanceId = instanceId,
timestampMs = timestampMs,
Expand Down Expand Up @@ -267,7 +268,7 @@ class UiLoadTraceEmitter(
private fun determineEndEvent(manualEnd: Boolean): TraceCompleteTrigger {
return if (manualEnd) {
TraceCompleteTrigger.MANUAL
} else if (hasRenderEvent) {
} else if (trackRender) {
TraceCompleteTrigger.RENDER
} else {
TraceCompleteTrigger.RESUME
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import io.embrace.android.embracesdk.internal.opentelemetry.embStartupActivityNa
import io.embrace.android.embracesdk.internal.session.lifecycle.ProcessStateListener
import io.embrace.android.embracesdk.internal.spans.PersistableEmbraceSpan
import io.embrace.android.embracesdk.internal.spans.SpanService
import io.embrace.android.embracesdk.internal.ui.hasRenderEvent
import io.embrace.android.embracesdk.internal.utils.Provider
import io.embrace.android.embracesdk.internal.utils.VersionChecker
import io.embrace.android.embracesdk.spans.EmbraceSpan
Expand Down Expand Up @@ -53,12 +54,12 @@ internal class AppStartupTraceEmitter(
private val processCreatedMs: Long?
private val additionalTrackedIntervals = ConcurrentLinkedQueue<TrackedInterval>()
private val customAttributes: MutableMap<String, String> = ConcurrentHashMap()
private val hasRenderEvent = startupHasRenderEvent(versionChecker)
private val trackRender = hasRenderEvent(versionChecker)
private val appStartupRootSpan = AtomicReference<PersistableEmbraceSpan?>(null)
private val dataCollectionComplete = AtomicBoolean(false)
private val traceEnd = if (manualEnd) {
TraceEnd.READY
} else if (hasRenderEvent) {
} else if (trackRender) {
TraceEnd.RENDERED
} else {
TraceEnd.RESUMED
Expand Down Expand Up @@ -277,7 +278,7 @@ internal class AppStartupTraceEmitter(
firstActivityInitMs = firstActivityInitStartMs,
activityInitStartMs = startupActivityPreCreatedMs ?: startupActivityInitStartMs,
activityInitEndMs = startupActivityInitEndMs,
uiLoadedMs = if (hasRenderEvent) firstFrameRenderedMs else startupActivityResumedMs,
uiLoadedMs = if (trackRender) firstFrameRenderedMs else startupActivityResumedMs,
traceEndTimeMs = traceEndTimeMs,
completed = completed,
)
Expand Down Expand Up @@ -363,7 +364,7 @@ internal class AppStartupTraceEmitter(
}

if (activityInitEndMs != null && uiLoadedMs != null) {
val uiLoadSpanName = if (hasRenderEvent) {
val uiLoadSpanName = if (trackRender) {
ACTIVITY_RENDER_SPAN
} else {
ACTIVITY_LOAD_SPAN
Expand Down Expand Up @@ -443,7 +444,5 @@ internal class AppStartupTraceEmitter(
} else {
null
}

fun startupHasRenderEvent(versionChecker: VersionChecker) = versionChecker.isAtLeast(VERSION_CODES.Q)
}
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
package io.embrace.android.embracesdk.internal.injection

import android.os.Build.VERSION_CODES
import io.embrace.android.embracesdk.internal.Systrace
import io.embrace.android.embracesdk.internal.capture.activity.UiLoadDataListener
import io.embrace.android.embracesdk.internal.capture.activity.UiLoadTraceEmitter
import io.embrace.android.embracesdk.internal.capture.activity.createActivityLoadEventEmitter
import io.embrace.android.embracesdk.internal.capture.activity.hasRenderEvent
import io.embrace.android.embracesdk.internal.capture.crumbs.ActivityBreadcrumbTracker
import io.embrace.android.embracesdk.internal.capture.crumbs.PushNotificationCaptureService
import io.embrace.android.embracesdk.internal.capture.startup.AppStartupDataCollector
import io.embrace.android.embracesdk.internal.capture.startup.AppStartupTraceEmitter
import io.embrace.android.embracesdk.internal.capture.startup.AppStartupTraceEmitter.Companion.startupHasRenderEvent
import io.embrace.android.embracesdk.internal.capture.startup.StartupService
import io.embrace.android.embracesdk.internal.capture.startup.StartupServiceImpl
import io.embrace.android.embracesdk.internal.capture.startup.StartupTracker
import io.embrace.android.embracesdk.internal.capture.webview.EmbraceWebViewService
import io.embrace.android.embracesdk.internal.capture.webview.WebViewService
import io.embrace.android.embracesdk.internal.config.ConfigService
import io.embrace.android.embracesdk.internal.session.lifecycle.ActivityLifecycleListener
import io.embrace.android.embracesdk.internal.ui.FirstDrawDetector
import io.embrace.android.embracesdk.internal.ui.createDrawEventEmitter
import io.embrace.android.embracesdk.internal.utils.BuildVersionChecker
import io.embrace.android.embracesdk.internal.utils.VersionChecker

Expand Down Expand Up @@ -69,11 +66,7 @@ internal class DataCaptureServiceModuleImpl @JvmOverloads constructor(
StartupTracker(
appStartupDataCollector = appStartupDataCollector,
activityLoadEventEmitter = activityLoadEventEmitter,
drawEventEmitter = if (startupHasRenderEvent(versionChecker)) {
FirstDrawDetector(logger = initModule.logger)
} else {
null
}
drawEventEmitter = createDrawEventEmitter(versionChecker, initModule.logger)
)
}

Expand All @@ -93,11 +86,7 @@ internal class DataCaptureServiceModuleImpl @JvmOverloads constructor(
if (uiLoadEventListener != null) {
createActivityLoadEventEmitter(
uiLoadEventListener = uiLoadEventListener,
firstDrawDetector = if (versionChecker.isAtLeast(VERSION_CODES.Q) && hasRenderEvent(versionChecker)) {
FirstDrawDetector(initModule.logger)
} else {
null
},
firstDrawDetector = createDrawEventEmitter(versionChecker, initModule.logger),
autoTraceEnabled = configService.autoDataCaptureBehavior.isUiLoadTracingTraceAll(),
clock = openTelemetryModule.openTelemetryClock,
versionChecker = versionChecker
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package io.embrace.android.embracesdk.internal.ui

import android.app.Activity
import android.os.Build
import android.os.Build.VERSION_CODES
import io.embrace.android.embracesdk.internal.handler.AndroidMainThreadHandler
import io.embrace.android.embracesdk.internal.logging.EmbLogger
import io.embrace.android.embracesdk.internal.utils.VersionChecker

/**
* Interface that allows callbacks to be registered and invoked when UI draw events happen
Expand All @@ -21,3 +26,19 @@
*/
fun unregisterFirstDrawCallback(activity: Activity)
}

fun createDrawEventEmitter(
versionChecker: VersionChecker,
logger: EmbLogger,
): DrawEventEmitter? = if (supportFrameCommitCallback(versionChecker)) {
FirstDrawDetector(logger)
} else if (hasRenderEvent(versionChecker)) {
HandlerMessageDrawDetector(AndroidMainThreadHandler())

Check warning on line 36 in embrace-android-features/src/main/kotlin/io/embrace/android/embracesdk/internal/ui/DrawEventEmitter.kt

View check run for this annotation

Codecov / codecov/patch

embrace-android-features/src/main/kotlin/io/embrace/android/embracesdk/internal/ui/DrawEventEmitter.kt#L36

Added line #L36 was not covered by tests
} else {
null
}

fun hasRenderEvent(versionChecker: VersionChecker) = versionChecker.isAtLeast(VERSION_CODES.M)

private fun supportFrameCommitCallback(versionChecker: VersionChecker) = versionChecker.isAtLeast(VERSION_CODES.Q) &&
(Build.VERSION.SDK_INT != VERSION_CODES.S && Build.VERSION.SDK_INT != VERSION_CODES.S_V2)
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package io.embrace.android.embracesdk.internal.ui

import android.app.Activity
import android.os.Build.VERSION_CODES.M
import android.os.Message
import androidx.annotation.RequiresApi
import io.embrace.android.embracesdk.internal.handler.MainThreadHandler

@RequiresApi(M)
class HandlerMessageDrawDetector(
private val handler: MainThreadHandler
) : DrawEventEmitter {

override fun registerFirstDrawCallback(
activity: Activity,
drawBeginCallback: () -> Unit,
firstFrameDeliveredCallback: () -> Unit,
) {
drawBeginCallback()
handler.sendMessageAtFrontOfQueue(
Message.obtain(handler.wrappedHandler, firstFrameDeliveredCallback).apply {
isAsynchronous = true
}
)
}

override fun unregisterFirstDrawCallback(activity: Activity) {
}

Check warning on line 28 in embrace-android-features/src/main/kotlin/io/embrace/android/embracesdk/internal/ui/HandlerMessageDrawDetector.kt

View check run for this annotation

Codecov / codecov/patch

embrace-android-features/src/main/kotlin/io/embrace/android/embracesdk/internal/ui/HandlerMessageDrawDetector.kt#L28

Added line #L28 was not covered by tests
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import io.embrace.android.embracesdk.internal.ClockTickingActivityLifecycleCallb
import io.embrace.android.embracesdk.internal.ClockTickingActivityLifecycleCallbacks.Companion.PRE_DURATION
import io.embrace.android.embracesdk.internal.ClockTickingActivityLifecycleCallbacks.Companion.STATE_DURATION
import io.embrace.android.embracesdk.internal.session.lifecycle.ActivityLifecycleListener
import io.embrace.android.embracesdk.internal.ui.hasRenderEvent
import io.embrace.android.embracesdk.internal.utils.BuildVersionChecker
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
Expand Down Expand Up @@ -223,21 +224,17 @@ internal class UiLoadExtTest {
stage = "resumeEnd",
timestampMs = START_TIME_MS + (POST_DURATION + STATE_DURATION + PRE_DURATION) * 3
),
// createEvent(
// stage = "render",
// timestampMs = START_TIME_MS + (POST_DURATION + STATE_DURATION + PRE_DURATION) * 3
// ),
// createEvent(
// stage = "renderEnd",
// timestampMs = START_TIME_MS + (POST_DURATION + STATE_DURATION + PRE_DURATION) * 3 + RENDER_DURATION
// ),
// createEvent(
// stage = "discard",
// timestampMs = START_TIME_MS + (POST_DURATION + STATE_DURATION + PRE_DURATION) * 3 + RENDER_DURATION + PRE_DURATION
// ),
createEvent(
stage = "render",
timestampMs = START_TIME_MS + (POST_DURATION + STATE_DURATION + PRE_DURATION) * 3
),
createEvent(
stage = "renderEnd",
timestampMs = START_TIME_MS + (POST_DURATION + STATE_DURATION + PRE_DURATION) * 3 + RENDER_DURATION
),
createEvent(
stage = "discard",
timestampMs = START_TIME_MS + (POST_DURATION + STATE_DURATION + PRE_DURATION) * 3 + PRE_DURATION
timestampMs = START_TIME_MS + (POST_DURATION + STATE_DURATION + PRE_DURATION) * 3 + RENDER_DURATION + PRE_DURATION
),
)

Expand All @@ -258,21 +255,17 @@ internal class UiLoadExtTest {
stage = "resumeEnd",
timestampMs = START_TIME_MS + (POST_DURATION + STATE_DURATION + PRE_DURATION) * 2
),
// createEvent(
// stage = "render",
// timestampMs = START_TIME_MS + (POST_DURATION + STATE_DURATION + PRE_DURATION) * 2
// ),
// createEvent(
// stage = "renderEnd",
// timestampMs = START_TIME_MS + (POST_DURATION + STATE_DURATION + PRE_DURATION) * 2 + RENDER_DURATION
// ),
// createEvent(
// stage = "discard",
// timestampMs = START_TIME_MS + (POST_DURATION + STATE_DURATION + PRE_DURATION) * 2 + RENDER_DURATION + PRE_DURATION
// ),
createEvent(
stage = "render",
timestampMs = START_TIME_MS + (POST_DURATION + STATE_DURATION + PRE_DURATION) * 2
),
createEvent(
stage = "renderEnd",
timestampMs = START_TIME_MS + (POST_DURATION + STATE_DURATION + PRE_DURATION) * 2 + RENDER_DURATION
),
createEvent(
stage = "discard",
timestampMs = START_TIME_MS + (POST_DURATION + STATE_DURATION + PRE_DURATION) * 2 + PRE_DURATION
timestampMs = START_TIME_MS + (POST_DURATION + STATE_DURATION + PRE_DURATION) * 2 + RENDER_DURATION + PRE_DURATION
),
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import io.embrace.android.embracesdk.internal.clock.nanosToMillis
import io.embrace.android.embracesdk.internal.payload.toNewPayload
import io.embrace.android.embracesdk.internal.spans.SpanService
import io.embrace.android.embracesdk.internal.spans.SpanSink
import io.embrace.android.embracesdk.internal.ui.hasRenderEvent
import io.embrace.android.embracesdk.internal.utils.BuildVersionChecker
import io.embrace.android.embracesdk.spans.EmbraceSpanEvent
import io.embrace.android.embracesdk.spans.ErrorCode
Expand Down
Loading
Loading