diff --git a/CHANGELOG.md b/CHANGELOG.md index 1823146d55..b52621fae5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Performance - Remove an unused lock from `SentryPerformanceProvider`, which was allocated on every cold start in `ContentProvider.onCreate` without ever being acquired ([#5871](https://github.com/getsentry/sentry-java/pull/5871)) +- Parse the app start profiling config with only the deserializer it needs instead of building a full `JsonSerializer` and `SentryOptions`, cutting 188 of 221 allocations on the main thread before `Application.onCreate` ([#5867](https://github.com/getsentry/sentry-java/pull/5867)) ## 8.51.0 diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/SentryPerformanceProvider.java b/sentry-android-core/src/main/java/io/sentry/android/core/SentryPerformanceProvider.java index c37d384aee..9d1f2e13ec 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/SentryPerformanceProvider.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/SentryPerformanceProvider.java @@ -13,7 +13,7 @@ import io.sentry.ILogger; import io.sentry.ISentryLifecycleToken; import io.sentry.ITransactionProfiler; -import io.sentry.JsonSerializer; +import io.sentry.JsonObjectReader; import io.sentry.SentryAppStartProfilingOptions; import io.sentry.SentryExecutorService; import io.sentry.SentryLevel; @@ -117,8 +117,7 @@ private void launchAppStartProfiler(final @NotNull AppStartMetrics appStartMetri try (final @NotNull Reader reader = new BufferedReader(new InputStreamReader(new FileInputStream(configFile)))) { final @Nullable SentryAppStartProfilingOptions profilingOptions = - new JsonSerializer(SentryOptions.empty()) - .deserialize(reader, SentryAppStartProfilingOptions.class); + deserializeProfilingConfig(reader); if (profilingOptions == null) { logger.log( @@ -166,6 +165,25 @@ private void launchAppStartProfiler(final @NotNull AppStartMetrics appStartMetri } } + /** + * Parses the app start profiling config with only the deserializer it needs. Going through {@link + * io.sentry.JsonSerializer} would allocate a full {@link SentryOptions} plus every registered + * deserializer on the main thread before {@code Application.onCreate}, to use exactly one of + * them. + * + *
Returns null on malformed input, matching what {@code JsonSerializer.deserialize} did, so + * callers keep reporting it as a deserialization failure rather than a read error. + */ + private @Nullable SentryAppStartProfilingOptions deserializeProfilingConfig( + final @NotNull Reader reader) { + try (final @NotNull JsonObjectReader jsonReader = new JsonObjectReader(reader)) { + return new SentryAppStartProfilingOptions.Deserializer().deserialize(jsonReader, logger); + } catch (Exception e) { + logger.log(SentryLevel.ERROR, "Error when deserializing", e); + return null; + } + } + private void createAndStartContinuousProfiler( final @NotNull Context context, final @NotNull SentryAppStartProfilingOptions profilingOptions, diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/SentryPerformanceProviderTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/SentryPerformanceProviderTest.kt index 254571181a..bff6cdfad3 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/SentryPerformanceProviderTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/SentryPerformanceProviderTest.kt @@ -153,6 +153,21 @@ class SentryPerformanceProviderTest { ) } + @Test + fun `when config file is malformed, profiler is not started`() { + fixture.getSut { config -> config.writeText("{\"profile_sampled\": tru") } + assertNull(AppStartMetrics.getInstance().appStartProfiler) + assertNull(AppStartMetrics.getInstance().appStartContinuousProfiler) + verify(fixture.logger).log(eq(SentryLevel.ERROR), eq("Error when deserializing"), any()) + verify(fixture.logger) + .log( + eq(SentryLevel.WARNING), + eq( + "Unable to deserialize the SentryAppStartProfilingOptions. App start profiling will not start." + ), + ) + } + @Test fun `when profiling is disabled, profiler is not started`() { fixture.getSut { config ->