Skip to content

Commit 0497277

Browse files
fix(android): Preserve app start activity counter
Keep the foreground headless guard from faking an observed activity so late standalone app start init still lets the first real activity classify startup and reset warm-start state correctly. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent b94ac3a commit 0497277

2 files changed

Lines changed: 20 additions & 6 deletions

File tree

sentry-android-core/src/main/java/io/sentry/android/core/performance/AppStartMetrics.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -479,12 +479,9 @@ private void handleHeadlessAppStartIfNeededOnMain() {
479479
if (activeActivitiesCounter.get() == 0) {
480480
// SDK init happened after Application.onCreate (e.g. deferred/late init inside an Activity):
481481
// we missed the Activity's onActivityCreated, but a foreground process means it was a real
482-
// launch, not a headless start. Don't emit a (fake) headless app-start; just keep the counter
483-
// consistent so the later onActivityDestroyed doesn't go negative. Gated on the listener so
484-
// only the standalone-app-start path (which is what could emit a headless transaction) is
485-
// affected.
482+
// launch, not a headless start. Gated on the listener so only the standalone-app-start path
483+
// (which is what could emit a headless transaction) is affected.
486484
if (headlessAppStartListener != null && ContextUtils.isForegroundImportance()) {
487-
activeActivitiesCounter.compareAndSet(0, 1);
488485
return;
489486
}
490487

@@ -629,7 +626,11 @@ public void onActivityStopped(@NonNull Activity activity) {
629626
public void onActivityDestroyed(@NonNull Activity activity) {
630627
CurrentActivityHolder.getInstance().clearActivity(activity);
631628

632-
final int remainingActivities = activeActivitiesCounter.decrementAndGet();
629+
int remainingActivities = activeActivitiesCounter.decrementAndGet();
630+
if (remainingActivities < 0) {
631+
activeActivitiesCounter.set(0);
632+
remainingActivities = 0;
633+
}
633634
// if the app is moving into background
634635
// as the next onActivityCreated will treat it as a new warm app start
635636
if (remainingActivities == 0 && !activity.isChangingConfigurations()) {

sentry-android-core/src/test/java/io/sentry/android/core/performance/AppStartMetricsTest.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,19 @@ class AppStartMetricsTest {
264264

265265
assertEquals(0, listenerCalls.get())
266266
assertEquals(AppStartMetrics.AppStartType.UNKNOWN, metrics.appStartType)
267+
268+
SystemClock.setCurrentTimeMillis(SystemClock.uptimeMillis() + 100)
269+
val activity = mock<Activity>()
270+
whenever(activity.isChangingConfigurations).thenReturn(false)
271+
metrics.onActivityCreated(activity, null)
272+
273+
assertEquals(AppStartMetrics.AppStartType.WARM, metrics.appStartType)
274+
275+
metrics.onActivityDestroyed(activity)
276+
SystemClock.setCurrentTimeMillis(SystemClock.uptimeMillis() + 100)
277+
metrics.onActivityCreated(mock<Activity>(), null)
278+
279+
assertEquals(AppStartMetrics.AppStartType.WARM, metrics.appStartType)
267280
}
268281

269282
@Test

0 commit comments

Comments
 (0)