Skip to content

Commit 8e5929c

Browse files
authored
New ANRv2 implementation based on ApplicationExitInfo (#2697)
1 parent 59a452f commit 8e5929c

File tree

96 files changed

+7201
-611
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

96 files changed

+7201
-611
lines changed

CHANGELOG.md

+10-1
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,18 @@
22

33
## Unreleased
44

5-
## Features
5+
### Features
66

77
- Add Screenshot and ViewHierarchy to integrations list ([#2698](https://github.com/getsentry/sentry-java/pull/2698))
8+
- New ANR detection based on [ApplicationExitInfo API](https://developer.android.com/reference/android/app/ApplicationExitInfo) ([#2697](https://github.com/getsentry/sentry-java/pull/2697))
9+
- This implementation completely replaces the old one (based on a watchdog) on devices running Android 11 and above:
10+
- New implementation provides more precise ANR events/ANR rate detection as well as system thread dump information. The new implementation reports ANRs exactly as Google Play Console, without producing false positives or missing important background ANR events.
11+
- However, despite producing many false positives, the old implementation is capable of better enriching ANR errors (which is not available with the new implementation), for example:
12+
- Capturing screenshots at the time of ANR event;
13+
- Capturing transactions and profiling data corresponding to the ANR event;
14+
- Auxiliary information (such as current memory load) at the time of ANR event.
15+
- If you would like us to provide support for the old approach working alongside the new one on Android 11 and above (e.g. for raising events for slow code on main thread), consider upvoting [this issue](https://github.com/getsentry/sentry-java/issues/2693).
16+
- The old watchdog implementation will continue working for older API versions (Android < 11)
817

918
### Fixes
1019

sentry-android-core/.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
INSTALLATION
22
last_crash
3+
.options-cache/
4+
.scope-cache/
35
/sentry

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

+25
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,29 @@ public final class io/sentry/android/core/AnrIntegration : io/sentry/Integration
5555
public final fun register (Lio/sentry/IHub;Lio/sentry/SentryOptions;)V
5656
}
5757

58+
public final class io/sentry/android/core/AnrIntegrationFactory {
59+
public fun <init> ()V
60+
public static fun create (Landroid/content/Context;Lio/sentry/android/core/BuildInfoProvider;)Lio/sentry/Integration;
61+
}
62+
63+
public final class io/sentry/android/core/AnrV2EventProcessor : io/sentry/BackfillingEventProcessor {
64+
public fun <init> (Landroid/content/Context;Lio/sentry/android/core/SentryAndroidOptions;Lio/sentry/android/core/BuildInfoProvider;)V
65+
public fun process (Lio/sentry/SentryEvent;Lio/sentry/Hint;)Lio/sentry/SentryEvent;
66+
}
67+
68+
public class io/sentry/android/core/AnrV2Integration : io/sentry/Integration, java/io/Closeable {
69+
public fun <init> (Landroid/content/Context;)V
70+
public fun close ()V
71+
public fun register (Lio/sentry/IHub;Lio/sentry/SentryOptions;)V
72+
}
73+
74+
public final class io/sentry/android/core/AnrV2Integration$AnrV2Hint : io/sentry/hints/BlockingFlushHint, io/sentry/hints/AbnormalExit, io/sentry/hints/Backfillable {
75+
public fun <init> (JLio/sentry/ILogger;JZZ)V
76+
public fun mechanism ()Ljava/lang/String;
77+
public fun shouldEnrich ()Z
78+
public fun timestamp ()Ljava/lang/Long;
79+
}
80+
5881
public final class io/sentry/android/core/AppComponentsBreadcrumbsIntegration : android/content/ComponentCallbacks2, io/sentry/Integration, java/io/Closeable {
5982
public fun <init> (Landroid/content/Context;)V
6083
public fun close ()V
@@ -297,9 +320,11 @@ public final class io/sentry/android/core/ViewHierarchyEventProcessor : io/sentr
297320
}
298321

299322
public final class io/sentry/android/core/cache/AndroidEnvelopeCache : io/sentry/cache/EnvelopeCache {
323+
public static final field LAST_ANR_REPORT Ljava/lang/String;
300324
public fun <init> (Lio/sentry/android/core/SentryAndroidOptions;)V
301325
public fun getDirectory ()Ljava/io/File;
302326
public static fun hasStartupCrashMarker (Lio/sentry/SentryOptions;)Z
327+
public static fun lastReportedAnr (Lio/sentry/SentryOptions;)Ljava/lang/Long;
303328
public fun store (Lio/sentry/SentryEnvelope;Lio/sentry/Hint;)V
304329
}
305330

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

+9-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import io.sentry.android.core.internal.util.SentryFrameMetricsCollector;
2020
import io.sentry.android.fragment.FragmentLifecycleIntegration;
2121
import io.sentry.android.timber.SentryTimberIntegration;
22+
import io.sentry.cache.PersistingOptionsObserver;
23+
import io.sentry.cache.PersistingScopeObserver;
2224
import io.sentry.compose.gestures.ComposeGestureTargetLocator;
2325
import io.sentry.internal.gestures.GestureTargetLocator;
2426
import io.sentry.transport.NoOpEnvelopeCache;
@@ -139,6 +141,7 @@ static void initializeIntegrationsAndProcessors(
139141
options.addEventProcessor(new PerformanceAndroidEventProcessor(options, activityFramesTracker));
140142
options.addEventProcessor(new ScreenshotEventProcessor(options, buildInfoProvider));
141143
options.addEventProcessor(new ViewHierarchyEventProcessor(options));
144+
options.addEventProcessor(new AnrV2EventProcessor(context, options, buildInfoProvider));
142145
options.setTransportGate(new AndroidTransportGate(context, options.getLogger()));
143146
final SentryFrameMetricsCollector frameMetricsCollector =
144147
new SentryFrameMetricsCollector(context, options, buildInfoProvider);
@@ -170,6 +173,11 @@ static void initializeIntegrationsAndProcessors(
170173
options.addCollector(new AndroidCpuCollector(options.getLogger(), buildInfoProvider));
171174
}
172175
options.setTransactionPerformanceCollector(new DefaultTransactionPerformanceCollector(options));
176+
177+
if (options.getCacheDirPath() != null) {
178+
options.addScopeObserver(new PersistingScopeObserver(options));
179+
options.addOptionsObserver(new PersistingOptionsObserver(options));
180+
}
173181
}
174182

175183
private static void installDefaultIntegrations(
@@ -213,7 +221,7 @@ private static void installDefaultIntegrations(
213221
// AppLifecycleIntegration has to be installed before AnrIntegration, because AnrIntegration
214222
// relies on AppState set by it
215223
options.addIntegration(new AppLifecycleIntegration());
216-
options.addIntegration(new AnrIntegration(context));
224+
options.addIntegration(AnrIntegrationFactory.create(context, buildInfoProvider));
217225

218226
// registerActivityLifecycleCallbacks is only available if Context is an AppContext
219227
if (context instanceof Application) {

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import io.sentry.SentryOptions;
1111
import io.sentry.exception.ExceptionMechanismException;
1212
import io.sentry.hints.AbnormalExit;
13+
import io.sentry.hints.TransactionEnd;
1314
import io.sentry.protocol.Mechanism;
1415
import io.sentry.util.HintUtils;
1516
import io.sentry.util.Objects;
@@ -141,7 +142,7 @@ public void close() throws IOException {
141142
* href="https://develop.sentry.dev/sdk/sessions/#crashed-abnormal-vs-errored">Develop Docs</a>
142143
* because we don't know whether the app has recovered after it or not.
143144
*/
144-
static final class AnrHint implements AbnormalExit {
145+
static final class AnrHint implements AbnormalExit, TransactionEnd {
145146

146147
private final boolean isBackgroundAnr;
147148

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package io.sentry.android.core;
2+
3+
import android.content.Context;
4+
import android.os.Build;
5+
import io.sentry.Integration;
6+
import org.jetbrains.annotations.ApiStatus;
7+
import org.jetbrains.annotations.NotNull;
8+
9+
@ApiStatus.Internal
10+
public final class AnrIntegrationFactory {
11+
12+
@NotNull
13+
public static Integration create(
14+
final @NotNull Context context, final @NotNull BuildInfoProvider buildInfoProvider) {
15+
if (buildInfoProvider.getSdkInfoVersion() >= Build.VERSION_CODES.R) {
16+
return new AnrV2Integration(context);
17+
} else {
18+
return new AnrIntegration(context);
19+
}
20+
}
21+
}

0 commit comments

Comments
 (0)