Skip to content

Commit 8823143

Browse files
committed
Unify handling
1 parent c8abed5 commit 8823143

File tree

4 files changed

+50
-45
lines changed

4 files changed

+50
-45
lines changed

sentry-android-core/api/sentry-android-core.api

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,7 @@ public class io/sentry/android/core/performance/AppStartMetrics : io/sentry/andr
462462
public fun setAppStartType (Lio/sentry/android/core/performance/AppStartMetrics$AppStartType;)V
463463
public fun setClassLoadedUptimeMs (J)V
464464
public fun shouldSendStartMeasurements ()Z
465+
public fun updateAppStartType (ZJ)V
465466
}
466467

467468
public final class io/sentry/android/core/performance/AppStartMetrics$AppStartType : java/lang/Enum {

sentry-android-core/src/main/java/io/sentry/android/core/ActivityLifecycleIntegration.java

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ public synchronized void onActivityCreated(
397397
if (!isAllActivityCallbacksAvailable) {
398398
onActivityPreCreated(activity, savedInstanceState);
399399
}
400-
setColdStart(savedInstanceState);
400+
setColdStart(savedInstanceState != null);
401401
if (hub != null && options != null && options.isEnableScreenTracking()) {
402402
final @Nullable String activityClassName = ClassUtil.getClassName(activity);
403403
hub.configureScope(scope -> scope.setScreen(activityClassName));
@@ -705,24 +705,9 @@ WeakHashMap<Activity, ISpan> getTtfdSpanMap() {
705705
return ttfdSpanMap;
706706
}
707707

708-
private void setColdStart(final @Nullable Bundle savedInstanceState) {
708+
private void setColdStart(final boolean hasBundle) {
709709
if (!firstActivityCreated) {
710-
final @NotNull TimeSpan appStartSpan = AppStartMetrics.getInstance().getAppStartTimeSpan();
711-
// If the app start span already started and stopped, it means the app restarted without
712-
// killing the process, so we are in a warm start
713-
// If the app has an invalid cold start, it means it was started in the background, like
714-
// via BroadcastReceiver, so we consider it a warm start
715-
if ((appStartSpan.hasStarted() && appStartSpan.hasStopped())
716-
|| (!AppStartMetrics.getInstance().isColdStartValid())) {
717-
AppStartMetrics.getInstance().restartAppStart(lastPausedUptimeMillis);
718-
AppStartMetrics.getInstance().setAppStartType(AppStartMetrics.AppStartType.WARM);
719-
} else {
720-
AppStartMetrics.getInstance()
721-
.setAppStartType(
722-
savedInstanceState == null
723-
? AppStartMetrics.AppStartType.COLD
724-
: AppStartMetrics.AppStartType.WARM);
725-
}
710+
AppStartMetrics.getInstance().updateAppStartType(hasBundle, lastPausedUptimeMillis);
726711
}
727712
}
728713

sentry-android-core/src/main/java/io/sentry/android/core/SentryPerformanceProvider.java

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
import android.os.Looper;
1515
import android.os.Process;
1616
import android.os.SystemClock;
17+
import android.util.Log;
18+
import androidx.annotation.NonNull;
1719
import io.sentry.ILogger;
1820
import io.sentry.ITransactionProfiler;
1921
import io.sentry.JsonSerializer;
@@ -33,8 +35,8 @@
3335
import java.io.FileNotFoundException;
3436
import java.io.InputStreamReader;
3537
import java.io.Reader;
36-
import java.util.concurrent.TimeUnit;
3738
import java.util.concurrent.atomic.AtomicBoolean;
39+
import java.util.concurrent.atomic.AtomicInteger;
3840
import org.jetbrains.annotations.ApiStatus;
3941
import org.jetbrains.annotations.NotNull;
4042
import org.jetbrains.annotations.Nullable;
@@ -52,6 +54,8 @@ public final class SentryPerformanceProvider extends EmptySecureContentProvider
5254

5355
private final @NotNull ILogger logger;
5456
private final @NotNull BuildInfoProvider buildInfoProvider;
57+
private final AtomicInteger activeActivitiesCounter = new AtomicInteger();
58+
private final AtomicBoolean firstDrawDone = new AtomicBoolean(false);
5559

5660
@TestOnly
5761
SentryPerformanceProvider(
@@ -201,35 +205,22 @@ private void onAppLaunched(
201205
appStartTimespan.setStartedAt(Process.getStartUptimeMillis());
202206
appStartMetrics.registerApplicationForegroundCheck(app);
203207

204-
final AtomicBoolean firstDrawDone = new AtomicBoolean(false);
205-
206208
activityCallback =
207209
new ActivityLifecycleCallbacksAdapter() {
208210

209211
@Override
210212
public void onActivityCreated(
211213
@NotNull Activity activity, @Nullable Bundle savedInstanceState) {
214+
Log.d("TAG", "onActivityCreated");
215+
activeActivitiesCounter.incrementAndGet();
216+
212217
// In case the SDK gets initialized async or the
213218
// ActivityLifecycleIntegration is not enabled (e.g on RN due to Context not being
214219
// instanceof Application)
215220
// the app start type never gets set
216-
if (appStartMetrics.getAppStartType() == AppStartMetrics.AppStartType.UNKNOWN) {
217-
// We consider pre-loaded application loads as warm starts
218-
// This usually happens e.g. due to BroadcastReceivers triggering
219-
// Application.onCreate only, but no Activity.onCreate
221+
if (!firstDrawDone.get()) {
220222
final long now = SystemClock.uptimeMillis();
221-
final long durationMs =
222-
now - appStartMetrics.getAppStartTimeSpan().getStartUptimeMs();
223-
if (durationMs > TimeUnit.SECONDS.toMillis(1)) {
224-
appStartMetrics.restartAppStart(now);
225-
appStartMetrics.setAppStartType(AppStartMetrics.AppStartType.WARM);
226-
} else {
227-
// Otherwise a non-null bundle determines the behavior
228-
appStartMetrics.setAppStartType(
229-
savedInstanceState == null
230-
? AppStartMetrics.AppStartType.COLD
231-
: AppStartMetrics.AppStartType.WARM);
232-
}
223+
AppStartMetrics.getInstance().updateAppStartType(savedInstanceState != null, now);
233224
}
234225
}
235226

@@ -245,20 +236,26 @@ public void onActivityStarted(@NotNull Activity activity) {
245236
new Handler(Looper.getMainLooper()).post(() -> onAppStartDone());
246237
}
247238
}
239+
240+
@Override
241+
public void onActivityDestroyed(@NonNull Activity activity) {
242+
final int remainingActivities = activeActivitiesCounter.decrementAndGet();
243+
// if the app is moving into background, reset firstDrawDone
244+
// as the next Activity is considered like a new app start
245+
if (remainingActivities == 0 && !activity.isChangingConfigurations()) {
246+
firstDrawDone.set(false);
247+
}
248+
}
248249
};
249250

250251
app.registerActivityLifecycleCallbacks(activityCallback);
251252
}
252253

253254
synchronized void onAppStartDone() {
254-
final @NotNull AppStartMetrics appStartMetrics = AppStartMetrics.getInstance();
255-
appStartMetrics.getSdkInitTimeSpan().stop();
256-
appStartMetrics.getAppStartTimeSpan().stop();
257-
258-
if (app != null) {
259-
if (activityCallback != null) {
260-
app.unregisterActivityLifecycleCallbacks(activityCallback);
261-
}
255+
if (!firstDrawDone.getAndSet(true)) {
256+
final @NotNull AppStartMetrics appStartMetrics = AppStartMetrics.getInstance();
257+
appStartMetrics.getSdkInitTimeSpan().stop();
258+
appStartMetrics.getAppStartTimeSpan().stop();
262259
}
263260
}
264261
}

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,4 +354,26 @@ public static void onContentProviderPostCreate(final @NotNull ContentProvider co
354354
measurement.setStoppedAt(now);
355355
}
356356
}
357+
358+
/**
359+
* @param hasBundle true if the activity onCreate had a non-null bundle
360+
* @param lastKnownStart in case the app start is too long, resets the app start timestamp to this
361+
* value
362+
*/
363+
public void updateAppStartType(final boolean hasBundle, final long lastKnownStart) {
364+
final @NotNull TimeSpan appStartSpan = getInstance().getAppStartTimeSpan();
365+
// If the app start span already started and stopped, it means the app restarted without
366+
// killing the process, so we are in a warm start
367+
// If the app has an invalid cold start, it means it was started in the background, like
368+
// via BroadcastReceiver, so we consider it a warm start
369+
if ((appStartSpan.hasStarted() && appStartSpan.hasStopped())
370+
|| (!getInstance().isColdStartValid())) {
371+
getInstance().restartAppStart(lastKnownStart);
372+
getInstance().setAppStartType(AppStartMetrics.AppStartType.WARM);
373+
} else {
374+
getInstance()
375+
.setAppStartType(
376+
hasBundle ? AppStartMetrics.AppStartType.WARM : AppStartMetrics.AppStartType.COLD);
377+
}
378+
}
357379
}

0 commit comments

Comments
 (0)