Skip to content

Commit

Permalink
Hook up Activity Open tracing component
Browse files Browse the repository at this point in the history
  • Loading branch information
bidetofevil committed Sep 13, 2024
1 parent c3524d9 commit 8f00ddb
Show file tree
Hide file tree
Showing 12 changed files with 340 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,9 @@ interface AutoDataCaptureBehavior {
* for apps with a lot of local files.
*/
fun isDiskUsageCaptureEnabled(): Boolean

/**
* Whether the SDK is configured to capture traces for the performance of the opening of Activities.
*/
fun isActivityOpenTracingEnabled(): Boolean
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class AutoDataCaptureBehaviorImpl(
const val CRASH_HANDLER_ENABLED_DEFAULT = true
const val CAPTURE_COMPOSE_ONCLICK_DEFAULT = false
const val REPORT_DISK_USAGE_DEFAULT = true
const val ACTIVITY_OPEN_ENABLED_DEFAULT = false
}

override fun isMemoryWarningCaptureEnabled(): Boolean {
Expand Down Expand Up @@ -80,4 +81,7 @@ class AutoDataCaptureBehaviorImpl(

override fun isDiskUsageCaptureEnabled(): Boolean =
local?.sdkConfig?.app?.reportDiskUsage ?: REPORT_DISK_USAGE_DEFAULT

override fun isActivityOpenTracingEnabled(): Boolean =
local?.sdkConfig?.automaticDataCaptureConfig?.activityOpenEnabled ?: ACTIVITY_OPEN_ENABLED_DEFAULT
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ internal class AutoDataCaptureBehaviorImplTest {
memoryServiceEnabled = false,
powerSaveModeServiceEnabled = false,
networkConnectivityServiceEnabled = false,
anrServiceEnabled = false
anrServiceEnabled = false,
activityOpenEnabled = true,
),
crashHandler = CrashHandlerLocalConfig(false),
composeConfig = ComposeLocalConfig(true),
Expand Down Expand Up @@ -53,6 +54,7 @@ internal class AutoDataCaptureBehaviorImplTest {
assertFalse(isNativeCrashCaptureEnabled())
assertTrue(isDiskUsageCaptureEnabled())
assertTrue(isThermalStatusCaptureEnabled())
assertFalse(isActivityOpenTracingEnabled())
}
}

Expand All @@ -68,6 +70,7 @@ internal class AutoDataCaptureBehaviorImplTest {
assertTrue(is3rdPartySigHandlerDetectionEnabled())
assertTrue(isNativeCrashCaptureEnabled())
assertFalse(isDiskUsageCaptureEnabled())
assertTrue(isActivityOpenTracingEnabled())
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import android.view.ViewTreeObserver
import android.view.Window
import io.embrace.android.embracesdk.annotation.StartupActivity
import io.embrace.android.embracesdk.internal.logging.EmbLogger
import io.embrace.android.embracesdk.internal.session.lifecycle.ActivityLifecycleListener
import io.embrace.android.embracesdk.internal.utils.VersionChecker

/**
Expand All @@ -37,6 +38,7 @@ import io.embrace.android.embracesdk.internal.utils.VersionChecker
*/
class StartupTracker(
private val appStartupDataCollector: AppStartupDataCollector,
private val activityOpenEventEmitter: ActivityLifecycleListener?,
private val logger: EmbLogger,
private val versionChecker: VersionChecker,
) : Application.ActivityLifecycleCallbacks {
Expand Down Expand Up @@ -117,6 +119,9 @@ class StartupTracker(
private fun startupComplete(application: Application) {
if (!startupDataCollectionComplete) {
application.unregisterActivityLifecycleCallbacks(this)
activityOpenEventEmitter?.apply {
application.registerActivityLifecycleCallbacks(this)
}
startupDataCollectionComplete = true
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.embrace.android.embracesdk.internal.injection

import io.embrace.android.embracesdk.internal.capture.activity.OpenEventEmitter
import io.embrace.android.embracesdk.internal.capture.activity.OpenEvents
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
Expand Down Expand Up @@ -35,7 +37,11 @@ interface DataCaptureServiceModule {
*/
val startupService: StartupService

val appStartupDataCollector: AppStartupDataCollector

val startupTracker: StartupTracker

val appStartupDataCollector: AppStartupDataCollector
val activityOpenTraceEmitter: OpenEvents

val activityOpenTracker: OpenEventEmitter?
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package io.embrace.android.embracesdk.internal.injection

import io.embrace.android.embracesdk.internal.Systrace
import io.embrace.android.embracesdk.internal.capture.activity.OpenEventEmitter
import io.embrace.android.embracesdk.internal.capture.activity.OpenEvents
import io.embrace.android.embracesdk.internal.capture.activity.OpenTraceEmitter
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
Expand Down Expand Up @@ -63,8 +66,28 @@ internal class DataCaptureServiceModuleImpl @JvmOverloads constructor(
override val startupTracker: StartupTracker by singleton {
StartupTracker(
appStartupDataCollector = appStartupDataCollector,
activityOpenEventEmitter = activityOpenTracker,
logger = initModule.logger,
versionChecker = versionChecker,
)
}

override val activityOpenTraceEmitter: OpenEvents by singleton {
OpenTraceEmitter(
spanService = openTelemetryModule.spanService,
versionChecker = versionChecker,
)
}

override val activityOpenTracker: OpenEventEmitter? by singleton {
if (configService.autoDataCaptureBehavior.isActivityOpenTracingEnabled()) {
OpenEventEmitter(
openEvents = activityOpenTraceEmitter,
clock = openTelemetryModule.openTelemetryClock,
versionChecker = versionChecker,
)
} else {
null
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import io.embrace.android.embracesdk.fakes.FakeClock
import io.embrace.android.embracesdk.fakes.FakeEmbLogger
import io.embrace.android.embracesdk.fakes.FakeSplashScreenActivity
import io.embrace.android.embracesdk.internal.logging.EmbLogger
import io.embrace.android.embracesdk.internal.session.lifecycle.ActivityLifecycleListener
import io.embrace.android.embracesdk.internal.utils.BuildVersionChecker
import org.junit.Assert.assertEquals
import org.junit.Before
Expand Down Expand Up @@ -37,6 +38,7 @@ internal class StartupTrackerTest {
dataCollector = FakeAppStartupDataCollector(clock = clock)
startupTracker = StartupTracker(
appStartupDataCollector = dataCollector,
activityOpenEventEmitter = object : ActivityLifecycleListener { },
logger = logger,
versionChecker = BuildVersionChecker
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,7 @@ class AutomaticDataCaptureLocalConfig(

@Json(name = "network_connectivity_info") val networkConnectivityServiceEnabled: Boolean? = null,

@Json(name = "anr_info") val anrServiceEnabled: Boolean? = null
@Json(name = "anr_info") val anrServiceEnabled: Boolean? = null,

@Json(name = "activity_open_info") val activityOpenEnabled: Boolean? = null
)
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import io.embrace.android.embracesdk.internal.utils.Provider
import org.json.JSONObject
import org.junit.Assert
import org.robolectric.Robolectric
import org.robolectric.android.controller.ActivityController
import java.io.IOException
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
Expand Down Expand Up @@ -153,6 +154,62 @@ internal fun IntegrationTestRule.Harness.recordSession(
return getLastSentSession()
}

internal fun IntegrationTestRule.Harness.openActivities(
addStartupActivity: Boolean = true,
startInBackground: Boolean = false,
createFirstActivity: Boolean = true,
activitiesAndActions: List<Pair<ActivityController<*>, () -> Unit>> = listOf(),
lifecycleEventGap: Long = 100L,
postActionDwell: Long = 20000L,
activityGap: Long = 50L,
): Envelope<SessionPayload>? {
val activityService = checkNotNull(Embrace.getImpl().activityService)
var lastActivity: ActivityController<*>? = if (addStartupActivity) {
Robolectric.buildActivity(Activity::class.java)
} else {
null
}?.apply {
create()
start()
activityService.onForeground()
resume()
pause()
if (startInBackground) {
stop()
activityService.onBackground()
overriddenClock.tick(10000L)
} else {
overriddenClock.tick(activityGap)
}
}
activitiesAndActions.forEachIndexed { index, (activityController, action) ->
if (index != 0 || createFirstActivity) {
activityController.create()
overriddenClock.tick(lifecycleEventGap)
}
activityController.start()
overriddenClock.tick(lifecycleEventGap)
if (index == 0 && startInBackground) {
activityService.onForeground()
}
activityController.resume()
overriddenClock.tick(lifecycleEventGap)
lastActivity?.stop()
overriddenClock.tick()

action()

overriddenClock.tick(postActionDwell)
activityController.pause()
overriddenClock.tick(activityGap)
lastActivity = activityController
}
lastActivity?.stop()
overriddenClock.tick()
activityService.onBackground()
return getLastSentSession()
}

/**
* Validates a payload against a golden file in the test resources. If the payload does not match
* the golden file, the assertion fails.
Expand Down
Loading

0 comments on commit 8f00ddb

Please sign in to comment.