Skip to content
Merged
Show file tree
Hide file tree
Changes from 19 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
7 changes: 4 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

### Fixes

- The app hang detection now correctly pauses and resumes when the game moves between background and foreground to prevent false positive events ([#2788](https://github.com/getsentry/sentry-unity/pull/2788))
- Migrated the native support for iOS and macOS to use the Obj-C flavour of `sentry-cocoa` ([#2767](https://github.com/getsentry/sentry-unity/pull/2767))
- The SDK now correctly synchronizes the `Environment` set on the `Scope` events coming from the native layer ([#2764](https://github.com/getsentry/sentry-unity/pull/2764))

Expand All @@ -21,9 +22,9 @@
- Bump .NET SDK from v6.5.0-33-g0140be0a to v6.8.0 ([#2761](https://github.com/getsentry/sentry-unity/pull/2761), [#2762](https://github.com/getsentry/sentry-unity/pull/2762), [#2776](https://github.com/getsentry/sentry-unity/pull/2776))
- [changelog](https://github.com/getsentry/sentry-dotnet/blob/main/CHANGELOG.md#680)
- [diff](https://github.com/getsentry/sentry-dotnet/compare/6.5.0-33-g0140be0a...6.8.0)
- Bump Native SDK from v0.15.3 to v0.16.0 ([#2769](https://github.com/getsentry/sentry-unity/pull/2769), [#2779](https://github.com/getsentry/sentry-unity/pull/2779))
- [changelog](https://github.com/getsentry/sentry-native/blob/master/CHANGELOG.md#0160)
- [diff](https://github.com/getsentry/sentry-native/compare/0.15.3...0.16.0)
- Bump Native SDK from v0.15.3 to v0.16.1 ([#2769](https://github.com/getsentry/sentry-unity/pull/2769), [#2779](https://github.com/getsentry/sentry-unity/pull/2779), [#2788](https://github.com/getsentry/sentry-unity/pull/2788))
- [changelog](https://github.com/getsentry/sentry-native/blob/master/CHANGELOG.md#0161)
- [diff](https://github.com/getsentry/sentry-native/compare/0.15.3...0.16.1)
- Bump Cocoa SDK from v9.21.0 to v9.23.0 ([#2767](https://github.com/getsentry/sentry-unity/pull/2767))
- [changelog](https://github.com/getsentry/sentry-cocoa/blob/main/CHANGELOG.md#9230)
- [diff](https://github.com/getsentry/sentry-cocoa/compare/9.21.0...9.23.0)
Expand Down
6 changes: 6 additions & 0 deletions src/Sentry.Unity.Android/SentryNative.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,20 @@ public static class SentryNative

internal static void AppHangHeartbeat() => AppHangHeartbeatStrategy();

internal static void AppHangPause() => AppHangPauseStrategy();

// libsentry.io
[DllImport("sentry")]
private static extern void sentry_reinstall_backend();

[DllImport("sentry")]
private static extern void sentry_app_hang_heartbeat();

[DllImport("sentry")]
private static extern void sentry_app_hang_pause();

// Testing
internal static Action ReinstallSentryNativeBackendStrategy = sentry_reinstall_backend;
internal static Action AppHangHeartbeatStrategy = sentry_app_hang_heartbeat;
internal static Action AppHangPauseStrategy = sentry_app_hang_pause;
}
4 changes: 3 additions & 1 deletion src/Sentry.Unity.Android/SentryNativeAndroid.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,9 @@ public static void Configure(SentryUnityOptions options)
if (options.NativeAppHangTrackingEnabled && options.NdkIntegrationEnabled)
{
Logger?.LogDebug("Starting the app-hang heartbeat coroutine.");
SentryMonoBehaviour.Instance.StartAppHangHeartbeat(SentryNative.AppHangHeartbeat);
SentryMonoBehaviour.Instance.StartAppHangHeartbeat(
SentryNative.AppHangHeartbeat,
SentryNative.AppHangPause);
Logger?.LogDebug("Disabling the C# ANR watchdog - sentry-native handles app hang detection.");
options.RemoveIntegration<AnrIntegration>();
}
Expand Down
4 changes: 3 additions & 1 deletion src/Sentry.Unity.Native/SentryNative.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,9 @@ internal static void Configure(SentryUnityOptions options, RuntimePlatform platf
if (options.NativeAppHangTrackingEnabled)
{
Logger?.LogDebug("Starting the app-hang heartbeat coroutine.");
SentryMonoBehaviour.Instance.StartAppHangHeartbeat(SentryNativeBridge.AppHangHeartbeat);
SentryMonoBehaviour.Instance.StartAppHangHeartbeat(
SentryNativeBridge.AppHangHeartbeat,
SentryNativeBridge.AppHangPause);

// sentry-native handles app-hang detection on the desktop platforms. Where it is effective, skip the
// C# ANR watchdog so a hang isn't reported twice (mirrors the iOS/sentry-cocoa behavior).
Expand Down
5 changes: 5 additions & 0 deletions src/Sentry.Unity.Native/SentryNativeBridge.cs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ internal static string GetDatabasePath(SentryUnityOptions options, IApplication?

internal static void AppHangHeartbeat() => sentry_app_hang_heartbeat();

internal static void AppHangPause() => sentry_app_hang_pause();

// libsentry.so
[DllImport(SentryLib)]
private static extern IntPtr sentry_options_new();
Expand Down Expand Up @@ -211,6 +213,9 @@ internal static string GetDatabasePath(SentryUnityOptions options, IApplication?
[DllImport(SentryLib)]
private static extern void sentry_options_set_app_hang_timeout(IntPtr options, ulong timeout);

[DllImport(SentryLib)]
private static extern void sentry_app_hang_pause();

[UnmanagedFunctionPointer(CallingConvention.Cdecl, SetLastError = true)]
private delegate void sentry_logger_function_t(int level, IntPtr message, IntPtr argsAddress, IntPtr userData);

Expand Down
13 changes: 13 additions & 0 deletions src/Sentry.Unity/SentryMonoBehaviour.AppHang.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public partial class SentryMonoBehaviour
private static readonly TimeSpan AppHangHeartbeatInterval = TimeSpan.FromSeconds(1);

private Coroutine? _appHangHeartbeat;
private Action? _appHangPause;

/// <summary>
/// Starts the app-hang heartbeat on the main thread at a fixed 1-second interval. Arming is
Expand All @@ -23,6 +24,18 @@ public partial class SentryMonoBehaviour
public Coroutine StartAppHangHeartbeat(Action heartbeat) =>
StartAppHangHeartbeat(heartbeat, AppHangHeartbeatInterval);

internal Coroutine StartAppHangHeartbeat(Action heartbeat, Action pause)
{
if (_appHangPause is not null)
{
ApplicationPausing -= _appHangPause;
}

_appHangPause = pause;
ApplicationPausing += pause;
return StartAppHangHeartbeat(heartbeat, AppHangHeartbeatInterval);
Comment thread
bitsandfoxes marked this conversation as resolved.
}
Comment thread
bitsandfoxes marked this conversation as resolved.

// Internal overload so tests can use a short interval.
internal Coroutine StartAppHangHeartbeat(Action heartbeat, TimeSpan interval)
{
Expand Down
19 changes: 19 additions & 0 deletions test/Sentry.Unity.Android.Tests/SentryNativeAndroidTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,25 @@ public void AppHangHeartbeat_InvokesNativeHeartbeat()
}
}

[Test]
public void AppHangPause_InvokesNativePause()
{
var pauseCalled = false;
var originalStrategy = Interlocked.Exchange(ref SentryNative.AppHangPauseStrategy,
() => pauseCalled = true);

try
{
SentryNative.AppHangPause();

Assert.True(pauseCalled);
}
finally
{
Interlocked.Exchange(ref SentryNative.AppHangPauseStrategy, originalStrategy);
}
}

[Test]
public void Configure_InstallationIdReturned_SetsDefaultUserId()
{
Expand Down
16 changes: 16 additions & 0 deletions test/Sentry.Unity.Tests/SentryMonoBehaviourAppHangTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,20 @@ public IEnumerator StartAppHangHeartbeat_StopsWhenObjectDestroyed()

Assert.AreEqual(countAfterDestroy, count);
}

[Test]
public void StartAppHangHeartbeat_PausesNativeDetectorWhenApplicationPauses()
{
var sut = GetSut();
var pauses = 0;

sut.StartAppHangHeartbeat(() => { }, () => pauses++);

sut.UpdatePauseStatus(true);
Assert.AreEqual(1, pauses);

sut.UpdatePauseStatus(false);
sut.UpdatePauseStatus(true);
Assert.AreEqual(2, pauses);
}
}
Loading