Skip to content

Commit 41c7551

Browse files
authored
feat: added AndroidNativeAnrEnabled and related options (#2671)
1 parent 17334bc commit 41c7551

5 files changed

Lines changed: 80 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## Unreleased
44

5+
### Features
6+
7+
- Added `AndroidNativeAnrEnabled` (default `true`) to enable ANR detection through `sentry-java` SDK. The native ANR integration monitors the Android UI thread. On API ≥ 30 this uses [ANR v2](https://docs.sentry.io/platforms/android/configuration/app-not-respond/) via `ApplicationExitInfo` to report OS-detected ANRs from prior runs; on API < 30 it falls back to an in-process watchdog. This is complementary to the Unity SDK's C# watchdog, which monitors the Unity player loop. ([#2671](https://github.com/getsentry/sentry-unity/pull/2671))
8+
59
### Dependencies
610

711
- Bump Cocoa SDK from v9.12.0 to v9.12.1 ([#2670](https://github.com/getsentry/sentry-unity/pull/2670))

src/Sentry.Unity.Android/SentryJava.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,11 @@ public void Init(SentryUnityOptions options)
140140
androidOptions.Call("setEnableScopeSync", options.NdkScopeSyncEnabled);
141141
androidOptions.Call("setNativeSdkName", "sentry.native.android.unity");
142142

143+
androidOptions.Call("setAnrEnabled", options.AndroidNativeAnrEnabled);
144+
androidOptions.Call("setEnableScopePersistence", options.AndroidNativeAnrEnabled);
145+
androidOptions.Call("setReportHistoricalAnrs", options.AndroidReportHistoricalAnrs);
146+
androidOptions.Call("setAttachAnrThreadDump", options.AndroidAttachAnrThreadDump);
147+
143148
using (var logsOptions = androidOptions.Call<AndroidJavaObject>("getLogs"))
144149
{
145150
logsOptions.Call("setEnabled", options.EnableLogs);
@@ -158,8 +163,6 @@ public void Init(SentryUnityOptions options)
158163
androidOptions.Call("setAttachScreenshot", false);
159164
androidOptions.Call("setEnableAutoSessionTracking", false);
160165
androidOptions.Call("setEnableActivityLifecycleBreadcrumbs", false);
161-
androidOptions.Call("setAnrEnabled", false);
162-
androidOptions.Call("setEnableScopePersistence", false);
163166
// Disable user interaction tracking to prevent conflicts with VR platforms (e.g., Oculus InputHooks)
164167
androidOptions.Call("setEnableUserInteractionBreadcrumbs", false);
165168
androidOptions.Call("setEnableUserInteractionTracing", false);

src/Sentry.Unity.Editor/Android/AndroidManifestConfiguration.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,9 @@ internal void ModifyManifest(string basePath)
218218
androidManifest.SetAutoTraceIdGeneration(false);
219219
androidManifest.SetAutoSessionTracking(false);
220220
androidManifest.SetAutoAppLifecycleBreadcrumbs(false);
221-
androidManifest.SetAnr(false);
222-
androidManifest.SetPersistentScopeObserver(false);
221+
androidManifest.SetAnr(_options.AndroidNativeAnrEnabled);
222+
androidManifest.SetPersistentScopeObserver(_options.AndroidNativeAnrEnabled);
223+
androidManifest.SetAttachAnrThreadDump(_options.AndroidAttachAnrThreadDump);
223224
// Disable user interaction tracking to prevent conflicts with VR platforms (e.g., Oculus InputHooks)
224225
androidManifest.SetEnableUserInteractionBreadcrumbs(false);
225226
androidManifest.SetEnableUserInteractionTracing(false);
@@ -495,6 +496,9 @@ internal void SetAnr(bool enableAnr)
495496
internal void SetPersistentScopeObserver(bool enableScopePersistence)
496497
=> SetMetaData($"{SentryPrefix}.enable-scope-persistence", enableScopePersistence.ToString());
497498

499+
internal void SetAttachAnrThreadDump(bool attachAnrThreadDump)
500+
=> SetMetaData($"{SentryPrefix}.anr.attach-thread-dumps", attachAnrThreadDump.ToString());
501+
498502
internal void SetNdkEnabled(bool enableNdk)
499503
=> SetMetaData($"{SentryPrefix}.ndk.enable", enableNdk.ToString());
500504

src/Sentry.Unity/SentryUnityOptions.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,36 @@ public sealed class SentryUnityOptions : SentryOptions
214214
/// </remarks>
215215
public NativeInitializationType AndroidNativeInitializationType { get; set; } = NativeInitializationType.Runtime;
216216

217+
/// <summary>
218+
/// Enables ANR detection on Android through the native (sentry-java) SDK.
219+
/// On API ≥ 30 this uses Android's <c>ApplicationExitInfo</c> to report ANRs detected by the OS
220+
/// in prior runs (ANR v2). On API &lt; 30, sentry-java falls back to its in-process watchdog.
221+
/// The Unity SDK's C# ANR watchdog continues to run on all API levels.
222+
/// </summary>
223+
/// <remarks>
224+
/// The Java and C# watchdogs observe different threads and are complementary: the Java watchdog
225+
/// monitors the Android UI (Looper) main thread, while the C# watchdog monitors the Unity engine
226+
/// main thread (the player loop). A hang that blocks both threads can produce one event from each.
227+
/// </remarks>
228+
public bool AndroidNativeAnrEnabled { get; set; } = true;
229+
230+
/// <summary>
231+
/// When <see cref="AndroidNativeAnrEnabled"/> is enabled, controls whether sentry-java reports historical ANRs
232+
/// recorded by the OS (<c>ApplicationExitInfo</c>) from prior runs. Has no effect when
233+
/// <see cref="AndroidNativeAnrEnabled"/> is <c>false</c>.
234+
/// </summary>
235+
/// <remarks>
236+
/// Runtime-only. There is no <c>AndroidManifest</c> meta-data tag for this option, so it is only
237+
/// applied when <see cref="AndroidNativeInitializationType"/> is <see cref="NativeInitializationType.Runtime"/>.
238+
/// </remarks>
239+
public bool AndroidReportHistoricalAnrs { get; set; } = false;
240+
241+
/// <summary>
242+
/// When <see cref="AndroidNativeAnrEnabled"/> is enabled, controls whether sentry-java attaches a thread dump
243+
/// to ANR events. Has no effect when <see cref="AndroidNativeAnrEnabled"/> is <c>false</c>.
244+
/// </summary>
245+
public bool AndroidAttachAnrThreadDump { get; set; } = false;
246+
217247
/// <summary>
218248
/// Whether the SDK should add the NDK integration for Android
219249
/// </summary>

test/Sentry.Unity.Editor.Tests/Android/AndroidManifestConfigurationTests.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,41 @@ public void ModifyManifest_UnityOptions_AndroidNativeSupportEnabled_InitTypeBuil
150150
StringAssert.Contains($"<meta-data android:name=\"io.sentry.dsn\" android:value=\"{_fixture.SentryUnityOptions.Dsn}\" />", manifest);
151151
}
152152

153+
[Test]
154+
public void ModifyManifest_AndroidNativeAnrEnabled_True_WritesAnrMetadataEnabled()
155+
{
156+
_fixture.SentryUnityOptions!.AndroidNativeAnrEnabled = true;
157+
var sut = _fixture.GetSut();
158+
159+
var manifest = WithAndroidManifest(basePath => sut.ModifyManifest(basePath));
160+
161+
StringAssert.Contains("<meta-data android:name=\"io.sentry.anr.enable\" android:value=\"True\" />", manifest);
162+
StringAssert.Contains("<meta-data android:name=\"io.sentry.enable-scope-persistence\" android:value=\"True\" />", manifest);
163+
}
164+
165+
[Test]
166+
public void ModifyManifest_AndroidNativeAnrEnabled_False_WritesAnrMetadataDisabled()
167+
{
168+
_fixture.SentryUnityOptions!.AndroidNativeAnrEnabled = false;
169+
var sut = _fixture.GetSut();
170+
171+
var manifest = WithAndroidManifest(basePath => sut.ModifyManifest(basePath));
172+
173+
StringAssert.Contains("<meta-data android:name=\"io.sentry.anr.enable\" android:value=\"False\" />", manifest);
174+
StringAssert.Contains("<meta-data android:name=\"io.sentry.enable-scope-persistence\" android:value=\"False\" />", manifest);
175+
}
176+
177+
[Test]
178+
public void ModifyManifest_AndroidAttachAnrThreadDump_FlowsThroughToManifest()
179+
{
180+
_fixture.SentryUnityOptions!.AndroidAttachAnrThreadDump = true;
181+
var sut = _fixture.GetSut();
182+
183+
var manifest = WithAndroidManifest(basePath => sut.ModifyManifest(basePath));
184+
185+
StringAssert.Contains("<meta-data android:name=\"io.sentry.anr.attach-thread-dumps\" android:value=\"True\" />", manifest);
186+
}
187+
153188
[Test]
154189
public void ModifyManifest_ManifestHasDsn()
155190
{

0 commit comments

Comments
 (0)