Skip to content

Commit b66bbdb

Browse files
authored
Merge d0764bd into 616c9f4
2 parents 616c9f4 + d0764bd commit b66bbdb

13 files changed

+504
-216
lines changed

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,20 @@ public class io/sentry/android/core/performance/ActivityLifecycleCallbacksAdapte
424424
public fun onActivityStopped (Landroid/app/Activity;)V
425425
}
426426

427+
public class io/sentry/android/core/performance/ActivityLifecycleSpanHelper {
428+
public fun <init> (Ljava/lang/String;)V
429+
public fun clear ()V
430+
public fun createAndStopOnCreateSpan (Lio/sentry/ISpan;)V
431+
public fun createAndStopOnStartSpan (Lio/sentry/ISpan;)V
432+
public fun getOnCreateSpan ()Lio/sentry/ISpan;
433+
public fun getOnCreateStartTimestamp ()Lio/sentry/SentryDate;
434+
public fun getOnStartSpan ()Lio/sentry/ISpan;
435+
public fun getOnStartStartTimestamp ()Lio/sentry/SentryDate;
436+
public fun saveSpanToAppStartMetrics ()V
437+
public fun setOnCreateStartTimestamp (Lio/sentry/SentryDate;)V
438+
public fun setOnStartStartTimestamp (Lio/sentry/SentryDate;)V
439+
}
440+
427441
public class io/sentry/android/core/performance/ActivityLifecycleTimeSpan : java/lang/Comparable {
428442
public fun <init> ()V
429443
public fun compareTo (Lio/sentry/android/core/performance/ActivityLifecycleTimeSpan;)I
@@ -436,6 +450,7 @@ public class io/sentry/android/core/performance/AppStartMetrics : io/sentry/andr
436450
public fun <init> ()V
437451
public fun addActivityLifecycleTimeSpans (Lio/sentry/android/core/performance/ActivityLifecycleTimeSpan;)V
438452
public fun clear ()V
453+
public fun createProcessInitSpan ()Lio/sentry/android/core/performance/TimeSpan;
439454
public fun getActivityLifecycleTimeSpans ()Ljava/util/List;
440455
public fun getAppStartProfiler ()Lio/sentry/ITransactionProfiler;
441456
public fun getAppStartSamplingDecision ()Lio/sentry/TracesSamplingDecision;
@@ -495,6 +510,7 @@ public class io/sentry/android/core/performance/TimeSpan : java/lang/Comparable
495510
public fun setStartUnixTimeMs (J)V
496511
public fun setStartedAt (J)V
497512
public fun setStoppedAt (J)V
513+
public fun setup (Ljava/lang/String;JJJ)V
498514
public fun start ()V
499515
public fun stop ()V
500516
}

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

Lines changed: 28 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
import io.sentry.TransactionOptions;
2929
import io.sentry.android.core.internal.util.ClassUtil;
3030
import io.sentry.android.core.internal.util.FirstDrawDoneListener;
31-
import io.sentry.android.core.performance.ActivityLifecycleTimeSpan;
31+
import io.sentry.android.core.performance.ActivityLifecycleSpanHelper;
3232
import io.sentry.android.core.performance.AppStartMetrics;
3333
import io.sentry.android.core.performance.TimeSpan;
3434
import io.sentry.protocol.MeasurementValue;
@@ -77,7 +77,7 @@ public final class ActivityLifecycleIntegration
7777
private @Nullable ISpan appStartSpan;
7878
private final @NotNull WeakHashMap<Activity, ISpan> ttidSpanMap = new WeakHashMap<>();
7979
private final @NotNull WeakHashMap<Activity, ISpan> ttfdSpanMap = new WeakHashMap<>();
80-
private final @NotNull WeakHashMap<Activity, ActivityLifecycleTimeSpan> activityLifecycleMap =
80+
private final @NotNull WeakHashMap<Activity, ActivityLifecycleSpanHelper> activitySpanHelpers =
8181
new WeakHashMap<>();
8282
private @NotNull SentryDate lastPausedTime = new SentryNanotimeDate(new Date(0), 0);
8383
private long lastPausedUptimeMillis = 0;
@@ -374,6 +374,9 @@ private void finishTransaction(
374374
@Override
375375
public void onActivityPreCreated(
376376
final @NotNull Activity activity, final @Nullable Bundle savedInstanceState) {
377+
final ActivityLifecycleSpanHelper helper =
378+
new ActivityLifecycleSpanHelper(activity.getClass().getName());
379+
activitySpanHelpers.put(activity, helper);
377380
// The very first activity start timestamp cannot be set to the class instantiation time, as it
378381
// may happen before an activity is started (service, broadcast receiver, etc). So we set it
379382
// here.
@@ -385,10 +388,7 @@ public void onActivityPreCreated(
385388
? hub.getOptions().getDateProvider().now()
386389
: AndroidDateUtils.getCurrentSentryDateTime();
387390
lastPausedUptimeMillis = SystemClock.uptimeMillis();
388-
389-
final @NotNull ActivityLifecycleTimeSpan timeSpan = new ActivityLifecycleTimeSpan();
390-
timeSpan.getOnCreate().setStartedAt(lastPausedUptimeMillis);
391-
activityLifecycleMap.put(activity, timeSpan);
391+
helper.setOnCreateStartTimestamp(lastPausedTime);
392392
}
393393

394394
@Override
@@ -415,27 +415,20 @@ public synchronized void onActivityCreated(
415415
@Override
416416
public void onActivityPostCreated(
417417
final @NotNull Activity activity, final @Nullable Bundle savedInstanceState) {
418-
if (appStartSpan == null) {
419-
activityLifecycleMap.remove(activity);
420-
return;
421-
}
422-
423-
final @Nullable ActivityLifecycleTimeSpan timeSpan = activityLifecycleMap.get(activity);
424-
if (timeSpan != null) {
425-
timeSpan.getOnCreate().stop();
426-
timeSpan.getOnCreate().setDescription(activity.getClass().getName() + ".onCreate");
418+
final ActivityLifecycleSpanHelper helper = activitySpanHelpers.get(activity);
419+
if (helper != null) {
420+
helper.createAndStopOnCreateSpan(appStartSpan);
427421
}
428422
}
429423

430424
@Override
431425
public void onActivityPreStarted(final @NotNull Activity activity) {
432-
final long now = SystemClock.uptimeMillis();
433-
if (appStartSpan == null) {
434-
return;
435-
}
436-
final @Nullable ActivityLifecycleTimeSpan timeSpan = activityLifecycleMap.get(activity);
437-
if (timeSpan != null) {
438-
timeSpan.getOnStart().setStartedAt(now);
426+
final ActivityLifecycleSpanHelper helper = activitySpanHelpers.get(activity);
427+
if (helper != null) {
428+
helper.setOnStartStartTimestamp(
429+
options != null
430+
? options.getDateProvider().now()
431+
: AndroidDateUtils.getCurrentSentryDateTime());
439432
}
440433
}
441434

@@ -458,14 +451,11 @@ public synchronized void onActivityStarted(final @NotNull Activity activity) {
458451

459452
@Override
460453
public void onActivityPostStarted(final @NotNull Activity activity) {
461-
final @Nullable ActivityLifecycleTimeSpan timeSpan = activityLifecycleMap.remove(activity);
462-
if (appStartSpan == null) {
463-
return;
464-
}
465-
if (timeSpan != null) {
466-
timeSpan.getOnStart().stop();
467-
timeSpan.getOnStart().setDescription(activity.getClass().getName() + ".onStart");
468-
AppStartMetrics.getInstance().addActivityLifecycleTimeSpans(timeSpan);
454+
final ActivityLifecycleSpanHelper helper = activitySpanHelpers.get(activity);
455+
if (helper != null) {
456+
helper.createAndStopOnStartSpan(appStartSpan);
457+
// Needed to handle hybrid SDKs
458+
helper.saveSpanToAppStartMetrics();
469459
}
470460
}
471461

@@ -524,7 +514,10 @@ public void onActivitySaveInstanceState(
524514

525515
@Override
526516
public synchronized void onActivityDestroyed(final @NotNull Activity activity) {
527-
activityLifecycleMap.remove(activity);
517+
final ActivityLifecycleSpanHelper helper = activitySpanHelpers.remove(activity);
518+
if (helper != null) {
519+
helper.clear();
520+
}
528521
if (performanceEnabled) {
529522

530523
// in case the appStartSpan isn't completed yet, we finish it as cancelled to avoid
@@ -564,7 +557,7 @@ private void clear() {
564557
firstActivityCreated = false;
565558
lastPausedTime = new SentryNanotimeDate(new Date(0), 0);
566559
lastPausedUptimeMillis = 0;
567-
activityLifecycleMap.clear();
560+
activitySpanHelpers.clear();
568561
}
569562

570563
private void finishSpan(final @Nullable ISpan span) {
@@ -609,8 +602,7 @@ private void onFirstFrameDrawn(final @Nullable ISpan ttfdSpan, final @Nullable I
609602
final @NotNull TimeSpan appStartTimeSpan = appStartMetrics.getAppStartTimeSpan();
610603
final @NotNull TimeSpan sdkInitTimeSpan = appStartMetrics.getSdkInitTimeSpan();
611604

612-
// in case the SentryPerformanceProvider is disabled it does not set the app start end times,
613-
// and we need to set the end time manually here
605+
// and we need to set the end time of the app start here, after the first frame is drawn.
614606
if (appStartTimeSpan.hasStarted() && appStartTimeSpan.hasNotStopped()) {
615607
appStartTimeSpan.stop();
616608
}
@@ -673,8 +665,8 @@ WeakHashMap<Activity, ITransaction> getActivitiesWithOngoingTransactions() {
673665

674666
@TestOnly
675667
@NotNull
676-
WeakHashMap<Activity, ActivityLifecycleTimeSpan> getActivityLifecycleMap() {
677-
return activityLifecycleMap;
668+
WeakHashMap<Activity, ActivityLifecycleSpanHelper> getActivitySpanHelpers() {
669+
return activitySpanHelpers;
678670
}
679671

680672
@TestOnly

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

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -213,14 +213,7 @@ public static Map<String, Object> getAppStartMeasurement() {
213213
final @NotNull AppStartMetrics metrics = AppStartMetrics.getInstance();
214214
final @NotNull List<Map<String, Object>> spans = new ArrayList<>();
215215

216-
final @NotNull TimeSpan processInitNativeSpan = new TimeSpan();
217-
processInitNativeSpan.setStartedAt(metrics.getAppStartTimeSpan().getStartUptimeMs());
218-
processInitNativeSpan.setStartUnixTimeMs(
219-
metrics.getAppStartTimeSpan().getStartTimestampMs()); // This has to go after setStartedAt
220-
processInitNativeSpan.setStoppedAt(metrics.getClassLoadedUptimeMs());
221-
processInitNativeSpan.setDescription("Process Initialization");
222-
223-
addTimeSpanToSerializedSpans(processInitNativeSpan, spans);
216+
addTimeSpanToSerializedSpans(metrics.createProcessInitSpan(), spans);
224217
addTimeSpanToSerializedSpans(metrics.getApplicationOnCreateTimeSpan(), spans);
225218

226219
for (final TimeSpan span : metrics.getContentProviderOnCreateTimeSpans()) {

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

Lines changed: 28 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
import io.sentry.SpanDataConvention;
1414
import io.sentry.SpanId;
1515
import io.sentry.SpanStatus;
16-
import io.sentry.android.core.performance.ActivityLifecycleTimeSpan;
1716
import io.sentry.android.core.performance.AppStartMetrics;
1817
import io.sentry.android.core.performance.TimeSpan;
1918
import io.sentry.protocol.App;
@@ -219,8 +218,8 @@ private boolean hasAppStartSpan(final @NotNull SentryTransaction txn) {
219218
private void attachAppStartSpans(
220219
final @NotNull AppStartMetrics appStartMetrics, final @NotNull SentryTransaction txn) {
221220

222-
// data will be filled only for cold and warm app starts
223-
if (appStartMetrics.getAppStartType() == AppStartMetrics.AppStartType.UNKNOWN) {
221+
// We include process init, content providers and application.onCreate spans only on cold start
222+
if (appStartMetrics.getAppStartType() != AppStartMetrics.AppStartType.COLD) {
224223
return;
225224
}
226225

@@ -234,80 +233,44 @@ private void attachAppStartSpans(
234233
@Nullable SpanId parentSpanId = null;
235234
final @NotNull List<SentrySpan> spans = txn.getSpans();
236235
for (final @NotNull SentrySpan span : spans) {
237-
if (span.getOp().contentEquals(APP_START_COLD)
238-
|| span.getOp().contentEquals(APP_START_WARM)) {
236+
if (span.getOp().contentEquals(APP_START_COLD)) {
239237
parentSpanId = span.getSpanId();
240238
break;
241239
}
242240
}
243241

244-
// We include process init, content providers and application.onCreate spans only on cold start
245-
if (appStartMetrics.getAppStartType() == AppStartMetrics.AppStartType.COLD) {
246-
// Process init
247-
final long classInitUptimeMs = appStartMetrics.getClassLoadedUptimeMs();
248-
final @NotNull TimeSpan appStartTimeSpan = appStartMetrics.getAppStartTimeSpan();
249-
if (appStartTimeSpan.hasStarted()
250-
&& Math.abs(classInitUptimeMs - appStartTimeSpan.getStartUptimeMs())
251-
<= MAX_PROCESS_INIT_APP_START_DIFF_MS) {
252-
final @NotNull TimeSpan processInitTimeSpan = new TimeSpan();
253-
processInitTimeSpan.setStartedAt(appStartTimeSpan.getStartUptimeMs());
254-
processInitTimeSpan.setStartUnixTimeMs(appStartTimeSpan.getStartTimestampMs());
255-
256-
processInitTimeSpan.setStoppedAt(classInitUptimeMs);
257-
processInitTimeSpan.setDescription("Process Initialization");
258-
259-
txn.getSpans()
260-
.add(
261-
timeSpanToSentrySpan(
262-
processInitTimeSpan, parentSpanId, traceId, APP_METRICS_PROCESS_INIT_OP));
263-
}
264-
265-
// Content Providers
266-
final @NotNull List<TimeSpan> contentProviderOnCreates =
267-
appStartMetrics.getContentProviderOnCreateTimeSpans();
268-
if (!contentProviderOnCreates.isEmpty()) {
269-
for (final @NotNull TimeSpan contentProvider : contentProviderOnCreates) {
270-
txn.getSpans()
271-
.add(
272-
timeSpanToSentrySpan(
273-
contentProvider, parentSpanId, traceId, APP_METRICS_CONTENT_PROVIDER_OP));
274-
}
275-
}
242+
// Process init
243+
final long classInitUptimeMs = appStartMetrics.getClassLoadedUptimeMs();
244+
final @NotNull TimeSpan appStartTimeSpan = appStartMetrics.getAppStartTimeSpan();
245+
if (appStartTimeSpan.hasStarted()
246+
&& Math.abs(classInitUptimeMs - appStartTimeSpan.getStartUptimeMs())
247+
<= MAX_PROCESS_INIT_APP_START_DIFF_MS) {
248+
final @NotNull TimeSpan processInitTimeSpan = appStartMetrics.createProcessInitSpan();
249+
250+
txn.getSpans()
251+
.add(
252+
timeSpanToSentrySpan(
253+
processInitTimeSpan, parentSpanId, traceId, APP_METRICS_PROCESS_INIT_OP));
254+
}
276255

277-
// Application.onCreate
278-
final @NotNull TimeSpan appOnCreate = appStartMetrics.getApplicationOnCreateTimeSpan();
279-
if (appOnCreate.hasStopped()) {
256+
// Content Providers
257+
final @NotNull List<TimeSpan> contentProviderOnCreates =
258+
appStartMetrics.getContentProviderOnCreateTimeSpans();
259+
if (!contentProviderOnCreates.isEmpty()) {
260+
for (final @NotNull TimeSpan contentProvider : contentProviderOnCreates) {
280261
txn.getSpans()
281262
.add(
282263
timeSpanToSentrySpan(
283-
appOnCreate, parentSpanId, traceId, APP_METRICS_APPLICATION_OP));
264+
contentProvider, parentSpanId, traceId, APP_METRICS_CONTENT_PROVIDER_OP));
284265
}
285266
}
286267

287-
// Activities
288-
final @NotNull List<ActivityLifecycleTimeSpan> activityLifecycleTimeSpans =
289-
appStartMetrics.getActivityLifecycleTimeSpans();
290-
for (ActivityLifecycleTimeSpan activityTimeSpan : activityLifecycleTimeSpans) {
291-
if (activityTimeSpan.getOnCreate().hasStarted()
292-
&& activityTimeSpan.getOnCreate().hasStopped()) {
293-
txn.getSpans()
294-
.add(
295-
timeSpanToSentrySpan(
296-
activityTimeSpan.getOnCreate(),
297-
parentSpanId,
298-
traceId,
299-
APP_METRICS_ACTIVITIES_OP));
300-
}
301-
if (activityTimeSpan.getOnStart().hasStarted()
302-
&& activityTimeSpan.getOnStart().hasStopped()) {
303-
txn.getSpans()
304-
.add(
305-
timeSpanToSentrySpan(
306-
activityTimeSpan.getOnStart(),
307-
parentSpanId,
308-
traceId,
309-
APP_METRICS_ACTIVITIES_OP));
310-
}
268+
// Application.onCreate
269+
final @NotNull TimeSpan appOnCreate = appStartMetrics.getApplicationOnCreateTimeSpan();
270+
if (appOnCreate.hasStopped()) {
271+
txn.getSpans()
272+
.add(
273+
timeSpanToSentrySpan(appOnCreate, parentSpanId, traceId, APP_METRICS_APPLICATION_OP));
311274
}
312275
}
313276

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

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,13 @@
33
import static io.sentry.Sentry.APP_START_PROFILING_CONFIG_FILE_NAME;
44

55
import android.annotation.SuppressLint;
6-
import android.app.Activity;
76
import android.app.Application;
87
import android.content.Context;
98
import android.content.pm.ProviderInfo;
109
import android.net.Uri;
1110
import android.os.Build;
12-
import android.os.Handler;
13-
import android.os.Looper;
1411
import android.os.Process;
1512
import android.os.SystemClock;
16-
import androidx.annotation.NonNull;
1713
import io.sentry.ILogger;
1814
import io.sentry.ITransactionProfiler;
1915
import io.sentry.JsonSerializer;
@@ -22,9 +18,7 @@
2218
import io.sentry.SentryLevel;
2319
import io.sentry.SentryOptions;
2420
import io.sentry.TracesSamplingDecision;
25-
import io.sentry.android.core.internal.util.FirstDrawDoneListener;
2621
import io.sentry.android.core.internal.util.SentryFrameMetricsCollector;
27-
import io.sentry.android.core.performance.ActivityLifecycleCallbacksAdapter;
2822
import io.sentry.android.core.performance.AppStartMetrics;
2923
import io.sentry.android.core.performance.TimeSpan;
3024
import java.io.BufferedReader;
@@ -33,7 +27,6 @@
3327
import java.io.FileNotFoundException;
3428
import java.io.InputStreamReader;
3529
import java.io.Reader;
36-
import java.util.concurrent.atomic.AtomicBoolean;
3730
import org.jetbrains.annotations.ApiStatus;
3831
import org.jetbrains.annotations.NotNull;
3932
import org.jetbrains.annotations.Nullable;
@@ -47,7 +40,6 @@ public final class SentryPerformanceProvider extends EmptySecureContentProvider
4740
private static final long sdkInitMillis = SystemClock.uptimeMillis();
4841

4942
private @Nullable Application app;
50-
private @Nullable Application.ActivityLifecycleCallbacks activityCallback;
5143

5244
private final @NotNull ILogger logger;
5345
private final @NotNull BuildInfoProvider buildInfoProvider;
@@ -199,37 +191,5 @@ private void onAppLaunched(
199191
final @NotNull TimeSpan appStartTimespan = appStartMetrics.getAppStartTimeSpan();
200192
appStartTimespan.setStartedAt(Process.getStartUptimeMillis());
201193
appStartMetrics.registerApplicationForegroundCheck(app);
202-
203-
final AtomicBoolean firstDrawDone = new AtomicBoolean(false);
204-
205-
activityCallback =
206-
new ActivityLifecycleCallbacksAdapter() {
207-
@Override
208-
public void onActivityStarted(@NonNull Activity activity) {
209-
if (firstDrawDone.get()) {
210-
return;
211-
}
212-
if (activity.getWindow() != null) {
213-
FirstDrawDoneListener.registerForNextDraw(
214-
activity, () -> onAppStartDone(), buildInfoProvider);
215-
} else {
216-
new Handler(Looper.getMainLooper()).post(() -> onAppStartDone());
217-
}
218-
}
219-
};
220-
221-
app.registerActivityLifecycleCallbacks(activityCallback);
222-
}
223-
224-
synchronized void onAppStartDone() {
225-
final @NotNull AppStartMetrics appStartMetrics = AppStartMetrics.getInstance();
226-
appStartMetrics.getSdkInitTimeSpan().stop();
227-
appStartMetrics.getAppStartTimeSpan().stop();
228-
229-
if (app != null) {
230-
if (activityCallback != null) {
231-
app.unregisterActivityLifecycleCallbacks(activityCallback);
232-
}
233-
}
234194
}
235195
}

0 commit comments

Comments
 (0)