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
@@ -1,5 +1,6 @@
package io.embrace.android.embracesdk.internal.injection

import io.embrace.android.embracesdk.internal.clock.nanosToMillis
import io.embrace.android.embracesdk.internal.config.behavior.SensitiveKeysBehavior
import io.embrace.android.embracesdk.internal.otel.config.OtelSdkConfig
import io.embrace.android.embracesdk.internal.otel.logs.LogSink
Expand Down Expand Up @@ -96,4 +97,6 @@ interface OpenTelemetryModule {
sensitiveKeysBehavior: SensitiveKeysBehavior,
bypassValidation: Boolean,
)

fun deviceStartTimeMs(): Long = openTelemetryClock.run { now() - nanoTime() }.nanosToMillis()
}
4 changes: 2 additions & 2 deletions embrace-android-features/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ dependencies {
compileOnly(project(":embrace-android-otel"))
compileOnly(platform(libs.opentelemetry.bom))
compileOnly(libs.opentelemetry.api)
compileOnly(libs.opentelemetry.sdk)
compileOnly(libs.opentelemetry.context)
compileOnly(libs.opentelemetry.semconv)
compileOnly(libs.opentelemetry.semconv.incubating)
implementation(libs.lifecycle.process)
Expand All @@ -37,7 +37,7 @@ dependencies {
testImplementation(project(":embrace-android-otel"))
testImplementation(platform(libs.opentelemetry.bom))
testImplementation(libs.opentelemetry.api)
testImplementation(libs.opentelemetry.sdk)
testImplementation(libs.opentelemetry.context)
testImplementation(libs.opentelemetry.semconv)
testImplementation(libs.opentelemetry.semconv.incubating)
testImplementation(libs.lifecycle.process)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ import androidx.annotation.RequiresApi
import io.embrace.android.embracesdk.annotation.CustomLoadTracedActivity
import io.embrace.android.embracesdk.annotation.LoadTracedActivity
import io.embrace.android.embracesdk.annotation.NotTracedActivity
import io.embrace.android.embracesdk.internal.clock.nanosToMillis
import io.embrace.android.embracesdk.internal.clock.Clock
import io.embrace.android.embracesdk.internal.session.lifecycle.ActivityLifecycleListener
import io.embrace.android.embracesdk.internal.ui.DrawEventEmitter
import io.embrace.android.embracesdk.internal.utils.VersionChecker
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaClock
import java.util.concurrent.ConcurrentHashMap

/**
Expand All @@ -24,7 +23,7 @@ fun createActivityLoadEventEmitter(
uiLoadEventListener: UiLoadEventListener,
firstDrawDetector: DrawEventEmitter?,
autoTraceEnabled: Boolean,
clock: OtelJavaClock,
clock: Clock,
versionChecker: VersionChecker,
): ActivityLifecycleListener {
val lifecycleEventEmitter = LifecycleEventEmitter(
Expand Down Expand Up @@ -120,7 +119,7 @@ private class LifecycleEventEmitter(
private val uiLoadEventListener: UiLoadEventListener,
private val drawEventEmitter: DrawEventEmitter?,
private val autoTraceEnabled: Boolean,
private val clock: OtelJavaClock,
private val clock: Clock,
) {

private val instanceStartTime: MutableMap<Int, Long> = ConcurrentHashMap()
Expand Down Expand Up @@ -224,5 +223,5 @@ private class LifecycleEventEmitter(

private fun Activity.isManualEnd(): Boolean = javaClass.isAnnotationPresent(CustomLoadTracedActivity::class.java)

private fun nowMs(): Long = clock.now().nanosToMillis()
private fun nowMs(): Long = clock.now()
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package io.embrace.android.embracesdk.internal.capture.startup

import android.os.Build.VERSION_CODES
import android.os.Process
import io.embrace.android.embracesdk.internal.clock.nanosToMillis
import io.embrace.android.embracesdk.internal.clock.Clock
import io.embrace.android.embracesdk.internal.logging.EmbLogger
import io.embrace.android.embracesdk.internal.logging.InternalErrorType
import io.embrace.android.embracesdk.internal.otel.attrs.embStartupActivityName
Expand All @@ -17,7 +17,6 @@ import io.embrace.android.embracesdk.internal.utils.VersionChecker
import io.embrace.android.embracesdk.spans.EmbraceSpan
import io.embrace.android.embracesdk.spans.EmbraceSpanEvent
import io.embrace.android.embracesdk.spans.ErrorCode
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaClock
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentLinkedQueue
import java.util.concurrent.atomic.AtomicBoolean
Expand All @@ -44,15 +43,19 @@ import java.util.concurrent.atomic.AtomicReference
*
*/
internal class AppStartupTraceEmitter(
private val clock: OtelJavaClock,
private val clock: Clock,
private val startupServiceProvider: Provider<StartupService?>,
private val spanService: SpanService,
private val versionChecker: VersionChecker,
private val logger: EmbLogger,
manualEnd: Boolean,
deviceStartTimestampMs: Long,
private val processCreatedMs: Long? = if (versionChecker.isAtLeast(VERSION_CODES.N)) {
deviceStartTimestampMs + Process.getStartElapsedRealtime()
} else {
null
},
) : AppStartupDataCollector, ProcessStateListener {
private val processCreateRequestedMs: Long?
private val processCreatedMs: Long?
private val additionalTrackedIntervals = ConcurrentLinkedQueue<TrackedInterval>()
private val customAttributes: MutableMap<String, String> = ConcurrentHashMap()
private val trackRender = hasRenderEvent(versionChecker)
Expand All @@ -67,20 +70,6 @@ internal class AppStartupTraceEmitter(
TraceEnd.RESUMED
}

init {
val timestampAtDeviceStart = nowMs() - clock.nanoTime().nanosToMillis()
processCreateRequestedMs = if (versionChecker.isAtLeast(VERSION_CODES.TIRAMISU)) {
timestampAtDeviceStart + Process.getStartRequestedElapsedRealtime()
} else {
null
}
processCreatedMs = if (versionChecker.isAtLeast(VERSION_CODES.N)) {
timestampAtDeviceStart + Process.getStartElapsedRealtime()
} else {
null
}
}

@Volatile
private var applicationInitStartMs: Long? = null

Expand Down Expand Up @@ -423,7 +412,7 @@ internal class AppStartupTraceEmitter(
private fun applicationActivityCreationGap(sdkInitEndMs: Long): Long? =
duration(applicationInitEndMs ?: sdkInitEndMs, firstActivityInitStartMs)

private fun nowMs(): Long = clock.now().nanosToMillis()
private fun nowMs(): Long = clock.now()

private fun EmbraceSdkSpan.addTraceMetadata() {
addCustomAttributes()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,13 @@ internal class DataCaptureServiceModuleImpl @JvmOverloads constructor(

override val appStartupDataCollector: AppStartupDataCollector by singleton {
AppStartupTraceEmitter(
clock = openTelemetryModule.openTelemetryClock,
clock = initModule.clock,
startupServiceProvider = { startupService },
spanService = openTelemetryModule.spanService,
versionChecker = versionChecker,
logger = initModule.logger,
manualEnd = configService.autoDataCaptureBehavior.isEndStartupWithAppReadyEnabled()
manualEnd = configService.autoDataCaptureBehavior.isEndStartupWithAppReadyEnabled(),
deviceStartTimestampMs = openTelemetryModule.deviceStartTimeMs()
)
}

Expand Down Expand Up @@ -88,7 +89,7 @@ internal class DataCaptureServiceModuleImpl @JvmOverloads constructor(
uiLoadEventListener = uiLoadEventListener,
firstDrawDetector = createDrawEventEmitter(versionChecker, initModule.logger),
autoTraceEnabled = configService.autoDataCaptureBehavior.isUiLoadTracingTraceAll(),
clock = openTelemetryModule.openTelemetryClock,
clock = initModule.clock,
versionChecker = versionChecker
)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import io.embrace.android.embracesdk.fakes.FakeNotTracedActivity
import io.embrace.android.embracesdk.fakes.FakeTracedActivity
import io.embrace.android.embracesdk.fakes.FakeUiLoadEventListener
import io.embrace.android.embracesdk.fakes.FakeUiLoadEventListener.EventData
import io.embrace.android.embracesdk.fakes.injection.FakeInitModule
import io.embrace.android.embracesdk.internal.ClockTickingActivityLifecycleCallbacks
import io.embrace.android.embracesdk.internal.ClockTickingActivityLifecycleCallbacks.Companion.POST_DURATION
import io.embrace.android.embracesdk.internal.ClockTickingActivityLifecycleCallbacks.Companion.PRE_DURATION
Expand Down Expand Up @@ -159,7 +158,7 @@ internal class UiLoadExtTest {
uiLoadEventListener = uiLoadEventListener,
firstDrawDetector = drawEventEmitter,
autoTraceEnabled = autoTraceEnabled,
clock = FakeInitModule(clock = clock).openTelemetryModule.openTelemetryClock,
clock = clock,
versionChecker = BuildVersionChecker
).apply {
RuntimeEnvironment.getApplication().registerActivityLifecycleCallbacks(this)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import io.embrace.android.embracesdk.internal.ui.hasRenderEvent
import io.embrace.android.embracesdk.internal.ui.supportFrameCommitCallback
import io.embrace.android.embracesdk.internal.utils.BuildVersionChecker
import io.embrace.android.embracesdk.spans.ErrorCode
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaClock
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
Expand Down Expand Up @@ -60,7 +59,6 @@ internal class AppStartupTraceEmitterTest {
private var hasFrameCommitEvent = true

private lateinit var clock: FakeClock
private lateinit var otelClock: OtelJavaClock
private lateinit var spanSink: SpanSink
private lateinit var spanService: SpanService
private lateinit var logger: FakeEmbLogger
Expand All @@ -69,7 +67,6 @@ internal class AppStartupTraceEmitterTest {
fun setUp() {
clock = FakeClock(processInitTime)
FakeInitModule(clock = clock).run {
otelClock = openTelemetryModule.openTelemetryClock
spanSink = openTelemetryModule.spanSink
spanService = openTelemetryModule.spanService
}
Expand Down Expand Up @@ -202,7 +199,7 @@ internal class AppStartupTraceEmitterTest {
@Config(sdk = [VERSION_CODES.TIRAMISU])
@Test
fun `abandon cold start after before manual end`() {
val emitter = createTraceEmitter(true).apply {
val emitter = createTraceEmitter(manualEnd = true).apply {
initApp(
hasAppInitEvents = true,
isColdStart = true
Expand Down Expand Up @@ -251,7 +248,7 @@ internal class AppStartupTraceEmitterTest {
@Config(sdk = [VERSION_CODES.TIRAMISU])
@Test
fun `abandon warm start after before manual end`() {
val emitter = createTraceEmitter(true).apply {
val emitter = createTraceEmitter(manualEnd = true).apply {
initApp(
hasAppInitEvents = true,
isColdStart = false
Expand Down Expand Up @@ -605,12 +602,18 @@ internal class AppStartupTraceEmitterTest {

private fun createTraceEmitter(manualEnd: Boolean = false) =
AppStartupTraceEmitter(
clock = otelClock,
clock = clock,
startupServiceProvider = { startupService },
spanService = spanService,
versionChecker = BuildVersionChecker,
logger = logger,
manualEnd = manualEnd,
deviceStartTimestampMs = DEFAULT_FAKE_CURRENT_TIME - 10000000L,
processCreatedMs = if (BuildVersionChecker.isAtLeast(VERSION_CODES.N)) {
DEFAULT_FAKE_CURRENT_TIME
} else {
null
}
)

private fun AppStartupTraceEmitter.simulateAppStartup(
Expand Down Expand Up @@ -699,9 +702,7 @@ internal class AppStartupTraceEmitterTest {
expectedCustomAttributes = mapOf("custom-attribute" to "true")
)

if (isColdStart && hasAppInitEvents) {
assertChildSpan(spanMap.processInitSpan(), traceStart, appInitTimestamps.applicationInitEnd)
} else {
if (!isColdStart) {
assertNull(spanMap.processInitSpan())
}

Expand Down Expand Up @@ -847,7 +848,7 @@ internal class AppStartupTraceEmitterTest {
}

private fun AppStartupTraceEmitter.fireEndEvent(
activityInitTimestamps: ActivityInitTimestamps
activityInitTimestamps: ActivityInitTimestamps,
) {
startupActivityInitEnd()
activityInitTimestamps.startupActivityEnd = clock.now()
Expand Down
Loading