Skip to content

Commit e6fa3a6

Browse files
runningcodeclaude
andcommitted
perf(android): Gate Compose class probes behind their features
The Compose gesture and view hierarchy class lookups ran during init regardless of configuration. Gate the gesture locators behind enableUserInteractionBreadcrumbs/Tracing and the Compose view hierarchy exporter behind attachViewHierarchy, so the Compose class probes only run when a feature that consumes them is enabled. Repeated probes of the Compose class across both blocks are deduplicated by LoadClass's cache. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent e6d30e8 commit e6fa3a6

2 files changed

Lines changed: 55 additions & 6 deletions

File tree

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

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -211,15 +211,18 @@ static void initializeIntegrationsAndProcessors(
211211

212212
final @NotNull LazyEvaluator<Boolean> isAndroidXScrollViewAvailable =
213213
loadClass.isClassAvailableLazy("androidx.core.view.ScrollingView", options);
214-
final boolean isComposeUpstreamAvailable =
215-
loadClass.isClassAvailable(COMPOSE_CLASS_NAME, options);
216214

217-
if (options.getGestureTargetLocators().isEmpty()) {
215+
// Gated behind the features that actually consume these so the Compose class lookups only run
216+
// when user interaction tracking or view hierarchy capture is enabled. Repeated COMPOSE_CLASS
217+
// probes across both blocks are deduplicated by LoadClass's cache.
218+
final boolean isUserInteractionEnabled =
219+
options.isEnableUserInteractionBreadcrumbs() || options.isEnableUserInteractionTracing();
220+
if (isUserInteractionEnabled && options.getGestureTargetLocators().isEmpty()) {
218221
final List<GestureTargetLocator> gestureTargetLocators = new ArrayList<>(2);
219222
gestureTargetLocators.add(new AndroidViewGestureTargetLocator(isAndroidXScrollViewAvailable));
220223

221224
final boolean isComposeAvailable =
222-
(isComposeUpstreamAvailable
225+
(loadClass.isClassAvailable(COMPOSE_CLASS_NAME, options)
223226
&& loadClass.isClassAvailable(
224227
SENTRY_COMPOSE_GESTURE_INTEGRATION_CLASS_NAME, options));
225228

@@ -229,8 +232,9 @@ static void initializeIntegrationsAndProcessors(
229232
options.setGestureTargetLocators(gestureTargetLocators);
230233
}
231234

232-
if (options.getViewHierarchyExporters().isEmpty()
233-
&& isComposeUpstreamAvailable
235+
if (options.isAttachViewHierarchy()
236+
&& options.getViewHierarchyExporters().isEmpty()
237+
&& loadClass.isClassAvailable(COMPOSE_CLASS_NAME, options)
234238
&& loadClass.isClassAvailable(
235239
SENTRY_COMPOSE_VIEW_HIERARCHY_INTEGRATION_CLASS_NAME, options)) {
236240

sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -806,6 +806,51 @@ class AndroidOptionsInitializerTest {
806806
assertTrue { fixture.sentryOptions.gestureTargetLocators[1] is ComposeGestureTargetLocator }
807807
}
808808

809+
@Test
810+
fun `does not set gesture target locators when user interaction tracking is disabled`() {
811+
fixture.sentryOptions.isEnableUserInteractionBreadcrumbs = false
812+
fixture.sentryOptions.isEnableUserInteractionTracing = false
813+
814+
fixture.initSutWithClassLoader(
815+
classesToLoad =
816+
listOf(
817+
AndroidOptionsInitializer.COMPOSE_CLASS_NAME,
818+
AndroidOptionsInitializer.SENTRY_COMPOSE_GESTURE_INTEGRATION_CLASS_NAME,
819+
)
820+
)
821+
822+
assertTrue { fixture.sentryOptions.gestureTargetLocators.isEmpty() }
823+
}
824+
825+
@Test
826+
fun `does not set compose view hierarchy exporter when attachViewHierarchy is disabled`() {
827+
// attachViewHierarchy defaults to false
828+
fixture.initSutWithClassLoader(
829+
classesToLoad =
830+
listOf(
831+
AndroidOptionsInitializer.COMPOSE_CLASS_NAME,
832+
AndroidOptionsInitializer.SENTRY_COMPOSE_VIEW_HIERARCHY_INTEGRATION_CLASS_NAME,
833+
)
834+
)
835+
836+
assertTrue { fixture.sentryOptions.viewHierarchyExporters.isEmpty() }
837+
}
838+
839+
@Test
840+
fun `sets compose view hierarchy exporter when attachViewHierarchy is enabled and compose is available`() {
841+
fixture.sentryOptions.isAttachViewHierarchy = true
842+
843+
fixture.initSutWithClassLoader(
844+
classesToLoad =
845+
listOf(
846+
AndroidOptionsInitializer.COMPOSE_CLASS_NAME,
847+
AndroidOptionsInitializer.SENTRY_COMPOSE_VIEW_HIERARCHY_INTEGRATION_CLASS_NAME,
848+
)
849+
)
850+
851+
assertTrue { fixture.sentryOptions.viewHierarchyExporters.size == 1 }
852+
}
853+
809854
@Test
810855
fun `AndroidMemoryCollector is set to options`() {
811856
fixture.initSut()

0 commit comments

Comments
 (0)