Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

- [ANR] Removed AndroidTransactionProfiler lock ([#4817](https://github.com/getsentry/sentry-java/pull/4817))

### Improvements

- [ANR] Defer some class availability checks ([#4825](https://github.com/getsentry/sentry-java/pull/4825))

### Dependencies

- Bump Native SDK from v0.11.2 to v0.11.3 ([#4810](https://github.com/getsentry/sentry-java/pull/4810))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import io.sentry.protocol.MeasurementValue;
import io.sentry.protocol.SentryId;
import io.sentry.util.AutoClosableReentrantLock;
import io.sentry.util.LazyEvaluator;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
Expand All @@ -30,7 +31,7 @@
*/
public final class ActivityFramesTracker {

private @Nullable FrameMetricsAggregator frameMetricsAggregator = null;
private @NotNull LazyEvaluator<FrameMetricsAggregator> frameMetricsAggregator;
private @NotNull final SentryAndroidOptions options;

private final @NotNull Map<SentryId, Map<String, @NotNull MeasurementValue>>
Expand All @@ -41,17 +42,18 @@ public final class ActivityFramesTracker {
private final @NotNull MainLooperHandler handler;
protected @NotNull AutoClosableReentrantLock lock = new AutoClosableReentrantLock();

private final @NotNull LazyEvaluator<Boolean> androidXAvailable;

public ActivityFramesTracker(
final @NotNull io.sentry.util.LoadClass loadClass,
final @NotNull SentryAndroidOptions options,
final @NotNull MainLooperHandler handler) {

final boolean androidXAvailable =
loadClass.isClassAvailable("androidx.core.app.FrameMetricsAggregator", options.getLogger());
androidXAvailable =
loadClass.isClassAvailableLazy(
"androidx.core.app.FrameMetricsAggregator", options.getLogger());
frameMetricsAggregator = new LazyEvaluator<>(() -> new FrameMetricsAggregator());

if (androidXAvailable) {
frameMetricsAggregator = new FrameMetricsAggregator();
}
this.options = options;
this.handler = handler;
}
Expand All @@ -67,15 +69,15 @@ public ActivityFramesTracker(
final @NotNull io.sentry.util.LoadClass loadClass,
final @NotNull SentryAndroidOptions options,
final @NotNull MainLooperHandler handler,
final @Nullable FrameMetricsAggregator frameMetricsAggregator) {
final @NotNull FrameMetricsAggregator frameMetricsAggregator) {

this(loadClass, options, handler);
this.frameMetricsAggregator = frameMetricsAggregator;
this.frameMetricsAggregator = new LazyEvaluator<>(() -> frameMetricsAggregator);
}

@VisibleForTesting
public boolean isFrameMetricsAggregatorAvailable() {
return frameMetricsAggregator != null
return androidXAvailable.getValue()
&& options.isEnableFramesTracking()
&& !options.isEnablePerformanceV2();
}
Expand All @@ -87,7 +89,8 @@ public void addActivity(final @NotNull Activity activity) {
return;
}

runSafelyOnUiThread(() -> frameMetricsAggregator.add(activity), "FrameMetricsAggregator.add");
runSafelyOnUiThread(
() -> frameMetricsAggregator.getValue().add(activity), "FrameMetricsAggregator.add");
snapshotFrameCountsAtStart(activity);
}
}
Expand All @@ -104,11 +107,11 @@ private void snapshotFrameCountsAtStart(final @NotNull Activity activity) {
return null;
}

if (frameMetricsAggregator == null) {
if (!androidXAvailable.getValue()) {
return null;
}

final @Nullable SparseIntArray[] framesRates = frameMetricsAggregator.getMetrics();
final @Nullable SparseIntArray[] framesRates = frameMetricsAggregator.getValue().getMetrics();

int totalFrames = 0;
int slowFrames = 0;
Expand Down Expand Up @@ -153,7 +156,7 @@ public void setMetrics(final @NotNull Activity activity, final @NotNull SentryId
// there was no
// Observers, See
// https://android.googlesource.com/platform/frameworks/base/+/140ff5ea8e2d99edc3fbe63a43239e459334c76b
runSafelyOnUiThread(() -> frameMetricsAggregator.remove(activity), null);
runSafelyOnUiThread(() -> frameMetricsAggregator.getValue().remove(activity), null);

final @Nullable FrameCounts frameCounts = diffFrameCountsAtEnd(activity);

Expand Down Expand Up @@ -215,8 +218,9 @@ public void setMetrics(final @NotNull Activity activity, final @NotNull SentryId
public void stop() {
try (final @NotNull ISentryLifecycleToken ignored = lock.acquire()) {
if (isFrameMetricsAggregatorAvailable()) {
runSafelyOnUiThread(() -> frameMetricsAggregator.stop(), "FrameMetricsAggregator.stop");
frameMetricsAggregator.reset();
runSafelyOnUiThread(
() -> frameMetricsAggregator.getValue().stop(), "FrameMetricsAggregator.stop");
frameMetricsAggregator.getValue().reset();
}
activityMeasurements.clear();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,8 @@ static void initializeIntegrationsAndProcessors(
options.setVersionDetector(new DefaultVersionDetector(options));
}

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import io.sentry.android.core.internal.util.ClassUtil;
import io.sentry.internal.gestures.GestureTargetLocator;
import io.sentry.internal.gestures.UiElement;
import io.sentry.util.LazyEvaluator;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
Expand All @@ -17,9 +18,10 @@ public final class AndroidViewGestureTargetLocator implements GestureTargetLocat

private static final String ORIGIN = "old_view_system";

private final boolean isAndroidXAvailable;
private final @NotNull LazyEvaluator<Boolean> isAndroidXAvailable;

public AndroidViewGestureTargetLocator(final boolean isAndroidXAvailable) {
public AndroidViewGestureTargetLocator(
final @NotNull LazyEvaluator<Boolean> isAndroidXAvailable) {
this.isAndroidXAvailable = isAndroidXAvailable;
}

Expand All @@ -33,7 +35,7 @@ public AndroidViewGestureTargetLocator(final boolean isAndroidXAvailable) {
if (targetType == UiElement.Type.CLICKABLE && isViewTappable(view)) {
return createUiElement(view);
} else if (targetType == UiElement.Type.SCROLLABLE
&& isViewScrollable(view, isAndroidXAvailable)) {
&& isViewScrollable(view, isAndroidXAvailable.getValue())) {
return createUiElement(view);
}
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import android.util.SparseIntArray
import androidx.core.app.FrameMetricsAggregator
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.sentry.ILogger
import io.sentry.SentryOptions
import io.sentry.protocol.MeasurementValue
import io.sentry.protocol.SentryId
import io.sentry.util.LazyEvaluator
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
Expand Down Expand Up @@ -34,12 +36,14 @@ class ActivityFramesTrackerTest {
options.isEnablePerformanceV2 = false
}

fun getSut(mockAggregator: Boolean = true): ActivityFramesTracker =
if (mockAggregator) {
ActivityFramesTracker(loadClass, options, handler, aggregator)
} else {
ActivityFramesTracker(loadClass, options, handler)
}
fun getSut(isAndroidxAvailable: Boolean = true): ActivityFramesTracker {
whenever(loadClass.isClassAvailableLazy(any(), any<ILogger>()))
.thenReturn(LazyEvaluator { isAndroidxAvailable })
whenever(loadClass.isClassAvailableLazy(any(), any<SentryOptions>()))
.thenReturn(LazyEvaluator { isAndroidxAvailable })

return ActivityFramesTracker(loadClass, options, handler, aggregator)
}
}

private val fixture = Fixture()
Expand Down Expand Up @@ -340,23 +344,20 @@ class ActivityFramesTrackerTest {

@Test
fun `addActivity does not throw if no AndroidX`() {
whenever(fixture.loadClass.isClassAvailable(any(), any<ILogger>())).thenReturn(false)
val sut = fixture.getSut(false)

sut.addActivity(fixture.activity)
}

@Test
fun `setMetrics does not throw if no AndroidX`() {
whenever(fixture.loadClass.isClassAvailable(any(), any<ILogger>())).thenReturn(false)
val sut = fixture.getSut(false)

sut.setMetrics(fixture.activity, fixture.sentryId)
}

@Test
fun `addActivity and setMetrics combined do not throw if no AndroidX`() {
whenever(fixture.loadClass.isClassAvailable(any(), any<ILogger>())).thenReturn(false)
val sut = fixture.getSut(false)

sut.addActivity(fixture.activity)
Expand All @@ -373,7 +374,6 @@ class ActivityFramesTrackerTest {

@Test
fun `stop does not throw if no AndroidX`() {
whenever(fixture.loadClass.isClassAvailable(any(), any<ILogger>())).thenReturn(false)
val sut = fixture.getSut(false)

sut.stop()
Expand All @@ -390,9 +390,13 @@ class ActivityFramesTrackerTest {

@Test
fun `takeMetrics returns null if no AndroidX`() {
whenever(fixture.loadClass.isClassAvailable(any(), any<ILogger>())).thenReturn(false)
val sut = fixture.getSut(false)

whenever(fixture.aggregator.metrics).thenReturn(emptyArray(), getArray())

sut.addActivity(fixture.activity)
sut.setMetrics(fixture.activity, fixture.sentryId)

assertNull(sut.takeMetrics(fixture.sentryId))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import io.sentry.Scope.IWithPropagationContext
import io.sentry.ScopeCallback
import io.sentry.SentryLevel.INFO
import io.sentry.android.core.SentryAndroidOptions
import io.sentry.util.LazyEvaluator
import kotlin.test.Test
import kotlin.test.assertEquals
import org.mockito.kotlin.any
Expand All @@ -38,7 +39,7 @@ class SentryGestureListenerClickTest {
SentryAndroidOptions().apply {
isEnableUserInteractionBreadcrumbs = true
isEnableUserInteractionTracing = true
gestureTargetLocators = listOf(AndroidViewGestureTargetLocator(true))
gestureTargetLocators = listOf(AndroidViewGestureTargetLocator(LazyEvaluator { true }))
dsn = "https://[email protected]/proj"
}
val scopes = mock<IScopes>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import io.sentry.ScopeCallback
import io.sentry.SentryLevel
import io.sentry.SentryLevel.INFO
import io.sentry.android.core.SentryAndroidOptions
import io.sentry.util.LazyEvaluator
import kotlin.test.Test
import kotlin.test.assertEquals
import org.mockito.kotlin.any
Expand All @@ -46,7 +47,7 @@ class SentryGestureListenerScrollTest {
dsn = "https://[email protected]/proj"
isEnableUserInteractionBreadcrumbs = true
isEnableUserInteractionTracing = true
gestureTargetLocators = listOf(AndroidViewGestureTargetLocator(true))
gestureTargetLocators = listOf(AndroidViewGestureTargetLocator(LazyEvaluator { true }))
}
val scopes = mock<IScopes>()
val scope = mock<IScope>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import io.sentry.TransactionOptions
import io.sentry.android.core.SentryAndroidOptions
import io.sentry.protocol.SentryId
import io.sentry.protocol.TransactionNameSource
import io.sentry.util.LazyEvaluator
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals
Expand Down Expand Up @@ -65,7 +66,8 @@ class SentryGestureListenerTracingTest {
options.tracesSampleRate = tracesSampleRate
options.isEnableUserInteractionTracing = isEnableUserInteractionTracing
options.isEnableUserInteractionBreadcrumbs = true
options.gestureTargetLocators = listOf(AndroidViewGestureTargetLocator(true))
options.gestureTargetLocators =
listOf(AndroidViewGestureTargetLocator(LazyEvaluator { true }))
options.isEnableAutoTraceIdGeneration = isEnableAutoTraceIdGeneration

whenever(scopes.options).thenReturn(options)
Expand Down
2 changes: 2 additions & 0 deletions sentry/api/sentry.api
Original file line number Diff line number Diff line change
Expand Up @@ -7086,6 +7086,8 @@ public class io/sentry/util/LoadClass {
public fun <init> ()V
public fun isClassAvailable (Ljava/lang/String;Lio/sentry/ILogger;)Z
public fun isClassAvailable (Ljava/lang/String;Lio/sentry/SentryOptions;)Z
public fun isClassAvailableLazy (Ljava/lang/String;Lio/sentry/ILogger;)Lio/sentry/util/LazyEvaluator;
public fun isClassAvailableLazy (Ljava/lang/String;Lio/sentry/SentryOptions;)Lio/sentry/util/LazyEvaluator;
public fun loadClass (Ljava/lang/String;Lio/sentry/ILogger;)Ljava/lang/Class;
}

Expand Down
10 changes: 10 additions & 0 deletions sentry/src/main/java/io/sentry/util/LoadClass.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,14 @@ public boolean isClassAvailable(
final @NotNull String clazz, final @Nullable SentryOptions options) {
return isClassAvailable(clazz, options != null ? options.getLogger() : null);
}

public LazyEvaluator<Boolean> isClassAvailableLazy(
final @NotNull String clazz, final @Nullable ILogger logger) {
return new LazyEvaluator<>(() -> isClassAvailable(clazz, logger));
}

public LazyEvaluator<Boolean> isClassAvailableLazy(
final @NotNull String clazz, final @Nullable SentryOptions options) {
return new LazyEvaluator<>(() -> isClassAvailable(clazz, options));
}
}
Loading