diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/EmbraceImpl.java b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/EmbraceImpl.java index e7d26fcda..39a4aae18 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/EmbraceImpl.java +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/EmbraceImpl.java @@ -373,17 +373,20 @@ private void startImpl(@NonNull Context context, final long endTimeMs = sdkClock.now(); started.set(true); Systrace.endSynchronous(); - Systrace.startSynchronous("startup-tracking"); - dataCaptureServiceModule.getStartupService().setSdkStartupInfo(startTimeMs, endTimeMs); - Systrace.endSynchronous(); + boolean inForeground = !essentialServiceModule.getProcessStateService().isInBackground(); // Attempt to send the startup event if the app is already in the foreground. We registered to send this when // we went to the foreground, but if an activity had already gone to the foreground, we may have missed // sending this, so to ensure the startup message is sent, we force it to be sent here. - if (!essentialServiceModule.getProcessStateService().isInBackground()) { + if (inForeground) { dataContainerModule.getEventService().sendStartupMoment(); } + Systrace.startSynchronous("startup-tracking"); + dataCaptureServiceModule.getStartupService().setSdkStartupInfo( + startTimeMs, endTimeMs, inForeground, Thread.currentThread().getName()); + Systrace.endSynchronous(); + // This should return immediately given that EmbraceSpansService initialization should be finished at this point // Put in emergency timeout just in case something unexpected happens so as to fail the SDK startup. moduleInitBootstrapper.waitForAsyncInit(); diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/capture/startup/StartupService.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/capture/startup/StartupService.kt index df76e45a1..53827fd3e 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/capture/startup/StartupService.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/capture/startup/StartupService.kt @@ -8,7 +8,7 @@ internal interface StartupService { /** * Sets the SDK startup info. This is called when the SDK is initialized. */ - fun setSdkStartupInfo(startTimeMs: Long, endTimeMs: Long) + fun setSdkStartupInfo(startTimeMs: Long, endTimeMs: Long, endedInForeground: Boolean, threadName: String?) /** * Returns the SDK startup duration. This is called when the session ends. diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/capture/startup/StartupServiceImpl.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/capture/startup/StartupServiceImpl.kt index f7e4e0f4e..fa80504e8 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/capture/startup/StartupServiceImpl.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/capture/startup/StartupServiceImpl.kt @@ -21,13 +21,17 @@ internal class StartupServiceImpl( @Volatile private var sdkStartupDurationMs: Long? = null - override fun setSdkStartupInfo(startTimeMs: Long, endTimeMs: Long) { + override fun setSdkStartupInfo(startTimeMs: Long, endTimeMs: Long, endedInForeground: Boolean, threadName: String?) { if (sdkStartupDurationMs == null) { spanService.recordCompletedSpan( name = "sdk-init", startTimeMs = startTimeMs, endTimeMs = endTimeMs, private = true, + attributes = mapOf( + "ended-in-foreground" to endedInForeground.toString(), + "thread-name" to (threadName ?: "unknown"), + ), ) } sdkInitStartMs = startTimeMs diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/capture/startup/AppStartupTraceEmitterTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/capture/startup/AppStartupTraceEmitterTest.kt index 62efde6d5..9cf35316f 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/capture/startup/AppStartupTraceEmitterTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/capture/startup/AppStartupTraceEmitterTest.kt @@ -206,7 +206,7 @@ internal class AppStartupTraceEmitterTest { appStartupTraceEmitter.applicationInitEnd() val applicationInitEnd = clock.now() clock.tick(50L) - checkNotNull(startupService).setSdkStartupInfo(sdkInitStart, sdkInitEnd) + checkNotNull(startupService).setSdkStartupInfo(sdkInitStart, sdkInitEnd, false, "main") appStartupTraceEmitter.startupActivityPreCreated() val startupActivityPreCreated = clock.now() clock.tick() @@ -256,7 +256,7 @@ internal class AppStartupTraceEmitterTest { clock.tick(30L) val sdkInitEnd = clock.now() clock.tick(400L) - checkNotNull(startupService).setSdkStartupInfo(sdkInitStart, sdkInitEnd) + checkNotNull(startupService).setSdkStartupInfo(sdkInitStart, sdkInitEnd, false, "main") appStartupTraceEmitter.startupActivityPreCreated() val startupActivityPreCreated = clock.now() clock.tick() @@ -311,7 +311,7 @@ internal class AppStartupTraceEmitterTest { appStartupTraceEmitter.applicationInitEnd() val applicationInitEnd = clock.now() clock.tick(50L) - checkNotNull(startupService).setSdkStartupInfo(sdkInitStart, sdkInitEnd) + checkNotNull(startupService).setSdkStartupInfo(sdkInitStart, sdkInitEnd, false, "main") appStartupTraceEmitter.startupActivityInitStart() val startupActivityStart = clock.now() clock.tick(180L) @@ -356,7 +356,7 @@ internal class AppStartupTraceEmitterTest { clock.tick(30L) val sdkInitEnd = clock.now() clock.tick(400L) - checkNotNull(startupService).setSdkStartupInfo(sdkInitStart, sdkInitEnd) + checkNotNull(startupService).setSdkStartupInfo(sdkInitStart, sdkInitEnd, false, "main") appStartupTraceEmitter.startupActivityInitStart() val startupActivityStart = clock.now() clock.tick(180L) @@ -398,7 +398,7 @@ internal class AppStartupTraceEmitterTest { val sdkInitStart = clock.now() clock.tick(30L) val sdkInitEnd = clock.now() - checkNotNull(startupService).setSdkStartupInfo(sdkInitStart, sdkInitEnd) + checkNotNull(startupService).setSdkStartupInfo(sdkInitStart, sdkInitEnd, false, "main") clock.tick(60001L) appStartupTraceEmitter.startupActivityPreCreated() val startupActivityPreCreated = clock.now() @@ -446,7 +446,7 @@ internal class AppStartupTraceEmitterTest { val sdkInitStart = clock.now() clock.tick(30L) val sdkInitEnd = clock.now() - checkNotNull(startupService).setSdkStartupInfo(sdkInitStart, sdkInitEnd) + checkNotNull(startupService).setSdkStartupInfo(sdkInitStart, sdkInitEnd, false, "main") clock.tick(60001L) appStartupTraceEmitter.startupActivityInitStart() val startupActivityStart = clock.now() diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/capture/startup/StartupServiceImplTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/capture/startup/StartupServiceImplTest.kt index be1d8777e..f51ccdfd2 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/capture/startup/StartupServiceImplTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/capture/startup/StartupServiceImplTest.kt @@ -5,6 +5,7 @@ import io.embrace.android.embracesdk.arch.assertIsTypePerformance import io.embrace.android.embracesdk.concurrency.BlockableExecutorService import io.embrace.android.embracesdk.fakes.FakeClock import io.embrace.android.embracesdk.fakes.injection.FakeInitModule +import io.embrace.android.embracesdk.findSpanAttribute import io.embrace.android.embracesdk.internal.clock.nanosToMillis import io.embrace.android.embracesdk.internal.spans.SpanService import io.embrace.android.embracesdk.internal.spans.SpanSink @@ -41,7 +42,7 @@ internal class StartupServiceImplTest { clock.tick(10L) val endTimeMillis = clock.now() spanService.initializeService(startTimeMillis) - startupService.setSdkStartupInfo(startTimeMillis, endTimeMillis) + startupService.setSdkStartupInfo(startTimeMillis, endTimeMillis, false, "main") val currentSpans = spanSink.completedSpans() assertEquals(1, currentSpans.size) with(currentSpans[0]) { @@ -52,29 +53,31 @@ internal class StartupServiceImplTest { assertIsTypePerformance() assertIsPrivateSpan() assertEquals(StatusCode.OK, status) + assertEquals("false", findSpanAttribute("ended-in-foreground")) + assertEquals("main", findSpanAttribute("thread-name")) } } @Test fun `second sdk startup span will not be recorded if you try to set the startup info twice`() { spanService.initializeService(10) - startupService.setSdkStartupInfo(10, 20) + startupService.setSdkStartupInfo(10, 20, false, "main") assertEquals(1, spanSink.completedSpans().size) - startupService.setSdkStartupInfo(10, 20) - startupService.setSdkStartupInfo(10, 20) + startupService.setSdkStartupInfo(10, 20, false, "main") + startupService.setSdkStartupInfo(10, 20, false, "main") assertEquals(1, spanSink.completedSpans().size) } @Test fun `sdk startup span recorded if the startup info is set before span service initializes`() { - startupService.setSdkStartupInfo(10, 20) + startupService.setSdkStartupInfo(10, 20, false, "main") spanService.initializeService(10) assertEquals(1, spanSink.completedSpans().size) } @Test fun `startup info available right after setting on the service`() { - startupService.setSdkStartupInfo(1111L, 3222L) + startupService.setSdkStartupInfo(1111L, 3222L, false, "main") assertEquals(1111L, startupService.getSdkInitStartMs()) assertEquals(3222L, startupService.getSdkInitEndMs()) assertEquals(2111L, startupService.getSdkStartupDuration(true)) diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/FakeStartupService.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/FakeStartupService.kt index 3456e0c78..79ea8cde3 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/FakeStartupService.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/FakeStartupService.kt @@ -5,9 +5,13 @@ import io.embrace.android.embracesdk.capture.startup.StartupService internal class FakeStartupService : StartupService { var sdkStartupDuration: Long? = null + var endedInForeground: Boolean? = null + var threadName: String? = null - override fun setSdkStartupInfo(startTimeMs: Long, endTimeMs: Long) { + override fun setSdkStartupInfo(startTimeMs: Long, endTimeMs: Long, endedInForeground: Boolean, threadName: String?) { sdkStartupDuration = endTimeMs - startTimeMs + this.endedInForeground = endedInForeground + this.threadName = threadName } override fun getSdkStartupDuration(coldStart: Boolean): Long? {