From e6a219e9b0049c28e4c669943ba469cf02bb74a1 Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Thu, 3 Mar 2022 15:34:59 +0100 Subject: [PATCH 1/6] feat: wip: close sentry instance when quitting the app --- src/Sentry.Unity.Native/SentryNative.cs | 11 ++++++ src/Sentry.Unity.Native/SentryNativeBridge.cs | 5 +++ src/Sentry.Unity/SentryMonoBehaviour.cs | 36 +++++++++++++++++-- src/Sentry.Unity/SentryUnity.cs | 7 +++- 4 files changed, 56 insertions(+), 3 deletions(-) diff --git a/src/Sentry.Unity.Native/SentryNative.cs b/src/Sentry.Unity.Native/SentryNative.cs index 2e1cec61f..b21071b0f 100644 --- a/src/Sentry.Unity.Native/SentryNative.cs +++ b/src/Sentry.Unity.Native/SentryNative.cs @@ -1,3 +1,4 @@ +using System; using Sentry.Extensibility; namespace Sentry.Unity.Native @@ -16,6 +17,11 @@ public static void Configure(SentryUnityOptions options) if (options.WindowsNativeSupportEnabled) { SentryNativeBridge.Init(options); + SentryMonoBehaviour.AttachOnApplicationQuittingOverride(() => + { + options?.DiagnosticLogger?.LogDebug("Closing the sentry-native SDK"); + SentryNativeBridge.Close(); + }); options.ScopeObserver = new NativeScopeObserver(options); options.EnableScopeSync = true; // options.CrashedLastRun = () => @@ -42,4 +48,9 @@ public static void Configure(SentryUnityOptions options) } } } + + internal class SentryMonoBehaviour : SentryMonoBehaviourInternal + { + public static void AttachOnApplicationQuittingOverride(Action action) => AttachOnApplicationQuitting(action); + } } diff --git a/src/Sentry.Unity.Native/SentryNativeBridge.cs b/src/Sentry.Unity.Native/SentryNativeBridge.cs index 1942fb1fd..224911c88 100644 --- a/src/Sentry.Unity.Native/SentryNativeBridge.cs +++ b/src/Sentry.Unity.Native/SentryNativeBridge.cs @@ -82,6 +82,8 @@ public static void Init(SentryUnityOptions options) sentry_init(cOptions); } + public static void Close() => sentry_close(); + // libsentry.so [DllImport("sentry")] private static extern IntPtr sentry_options_new(); @@ -167,6 +169,9 @@ private static void nativeLog(int cLevel, string message, IntPtr args, IntPtr us [DllImport("sentry")] private static extern void sentry_init(IntPtr options); + [DllImport("sentry")] + private static extern int sentry_close(); + /// /// Re-installs the sentry-native backend essentially retaking the signal handlers. /// diff --git a/src/Sentry.Unity/SentryMonoBehaviour.cs b/src/Sentry.Unity/SentryMonoBehaviour.cs index 594c20579..34333bc87 100644 --- a/src/Sentry.Unity/SentryMonoBehaviour.cs +++ b/src/Sentry.Unity/SentryMonoBehaviour.cs @@ -50,6 +50,15 @@ internal partial class SentryMonoBehaviour /// public event Action? ApplicationPausing; + /// + /// Hook to receive an event when the application is quitting. + /// + /// This is not guaranteed to be called on all platforms. See Unity docs for more details: + /// https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnApplicationQuit.html + /// + /// + public event Action? ApplicationQuitting; + // Keeping internal track of running state because OnApplicationPause and OnApplicationFocus get called during startup and would fire false resume events private bool _isRunning = true; @@ -116,8 +125,31 @@ internal void OnApplicationFocus(bool hasFocus) } } - // The GameObject has to destroy itself since it was created with HideFlags.HideAndDontSave - private void OnApplicationQuit() => Destroy(gameObject); + private void OnApplicationQuit() + { + try + { + ApplicationQuitting?.Invoke(); + } + catch (Exception e) + { + Debug.LogWarningFormat("ApplicationQuitting.Invoke() threw an exception %s", e.ToString()); + } + + // The GameObject has to destroy itself since it was created with HideFlags.HideAndDontSave + Destroy(gameObject); + } + } + + /// + /// Sentry-Unity SDK internal class for other Sentry.Unity.* assemblies. + /// You should not use this directly in your application. + /// + public class SentryMonoBehaviourInternal + { + /// This is `protected internal` to be semi-hidden from users. + protected internal static void AttachOnApplicationQuitting(Action action) => + SentryMonoBehaviour.Instance.ApplicationQuitting += action; } /// diff --git a/src/Sentry.Unity/SentryUnity.cs b/src/Sentry.Unity/SentryUnity.cs index e7dc73b19..f5059aa1e 100644 --- a/src/Sentry.Unity/SentryUnity.cs +++ b/src/Sentry.Unity/SentryUnity.cs @@ -31,7 +31,12 @@ public static void Init(SentryUnityOptions sentryUnityOptions) if (sentryUnityOptions.ShouldInitializeSdk()) { sentryUnityOptions.DiagnosticLogger?.LogDebug(sentryUnityOptions.ToString()); - SentrySdk.Init(sentryUnityOptions); + var sentryDotNet = SentrySdk.Init(sentryUnityOptions); + SentryMonoBehaviour.Instance.ApplicationQuitting += () => + { + sentryUnityOptions.DiagnosticLogger?.LogDebug("Closing the sentry-dotnet SDK"); + sentryDotNet.Dispose(); + }; } } } From 3246dae2bc1e78f311ae64459177232626b13004 Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Fri, 4 Mar 2022 10:35:49 +0100 Subject: [PATCH 2/6] refactor: use Application.Quitting instead of SentryMonoBehavior --- src/Sentry.Unity.Native/SentryNative.cs | 13 +++---- src/Sentry.Unity/Integrations/IApplication.cs | 3 +- src/Sentry.Unity/SentryMonoBehaviour.cs | 36 ++----------------- src/Sentry.Unity/SentryUnity.cs | 3 +- 4 files changed, 10 insertions(+), 45 deletions(-) diff --git a/src/Sentry.Unity.Native/SentryNative.cs b/src/Sentry.Unity.Native/SentryNative.cs index b21071b0f..a5005a404 100644 --- a/src/Sentry.Unity.Native/SentryNative.cs +++ b/src/Sentry.Unity.Native/SentryNative.cs @@ -1,5 +1,5 @@ -using System; using Sentry.Extensibility; +using Sentry.Unity.Integrations; namespace Sentry.Unity.Native { @@ -17,11 +17,11 @@ public static void Configure(SentryUnityOptions options) if (options.WindowsNativeSupportEnabled) { SentryNativeBridge.Init(options); - SentryMonoBehaviour.AttachOnApplicationQuittingOverride(() => + ApplicationAdapter.Instance.Quitting += () => { - options?.DiagnosticLogger?.LogDebug("Closing the sentry-native SDK"); + options.DiagnosticLogger?.LogDebug("Closing the sentry-native SDK"); SentryNativeBridge.Close(); - }); + }; options.ScopeObserver = new NativeScopeObserver(options); options.EnableScopeSync = true; // options.CrashedLastRun = () => @@ -48,9 +48,4 @@ public static void Configure(SentryUnityOptions options) } } } - - internal class SentryMonoBehaviour : SentryMonoBehaviourInternal - { - public static void AttachOnApplicationQuittingOverride(Action action) => AttachOnApplicationQuitting(action); - } } diff --git a/src/Sentry.Unity/Integrations/IApplication.cs b/src/Sentry.Unity/Integrations/IApplication.cs index 7df8a90d8..b078d507e 100644 --- a/src/Sentry.Unity/Integrations/IApplication.cs +++ b/src/Sentry.Unity/Integrations/IApplication.cs @@ -16,7 +16,8 @@ internal interface IApplication RuntimePlatform Platform { get; } } - internal sealed class ApplicationAdapter : IApplication + /// Semi-internal class to be used by other Sentry.Unity assemblies + public sealed class ApplicationAdapter : IApplication { public static readonly ApplicationAdapter Instance = new(); diff --git a/src/Sentry.Unity/SentryMonoBehaviour.cs b/src/Sentry.Unity/SentryMonoBehaviour.cs index 34333bc87..594c20579 100644 --- a/src/Sentry.Unity/SentryMonoBehaviour.cs +++ b/src/Sentry.Unity/SentryMonoBehaviour.cs @@ -50,15 +50,6 @@ internal partial class SentryMonoBehaviour /// public event Action? ApplicationPausing; - /// - /// Hook to receive an event when the application is quitting. - /// - /// This is not guaranteed to be called on all platforms. See Unity docs for more details: - /// https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnApplicationQuit.html - /// - /// - public event Action? ApplicationQuitting; - // Keeping internal track of running state because OnApplicationPause and OnApplicationFocus get called during startup and would fire false resume events private bool _isRunning = true; @@ -125,31 +116,8 @@ internal void OnApplicationFocus(bool hasFocus) } } - private void OnApplicationQuit() - { - try - { - ApplicationQuitting?.Invoke(); - } - catch (Exception e) - { - Debug.LogWarningFormat("ApplicationQuitting.Invoke() threw an exception %s", e.ToString()); - } - - // The GameObject has to destroy itself since it was created with HideFlags.HideAndDontSave - Destroy(gameObject); - } - } - - /// - /// Sentry-Unity SDK internal class for other Sentry.Unity.* assemblies. - /// You should not use this directly in your application. - /// - public class SentryMonoBehaviourInternal - { - /// This is `protected internal` to be semi-hidden from users. - protected internal static void AttachOnApplicationQuitting(Action action) => - SentryMonoBehaviour.Instance.ApplicationQuitting += action; + // The GameObject has to destroy itself since it was created with HideFlags.HideAndDontSave + private void OnApplicationQuit() => Destroy(gameObject); } /// diff --git a/src/Sentry.Unity/SentryUnity.cs b/src/Sentry.Unity/SentryUnity.cs index f5059aa1e..f83eae333 100644 --- a/src/Sentry.Unity/SentryUnity.cs +++ b/src/Sentry.Unity/SentryUnity.cs @@ -1,6 +1,7 @@ using System; using System.ComponentModel; using Sentry.Extensibility; +using Sentry.Unity.Integrations; namespace Sentry.Unity { @@ -32,7 +33,7 @@ public static void Init(SentryUnityOptions sentryUnityOptions) { sentryUnityOptions.DiagnosticLogger?.LogDebug(sentryUnityOptions.ToString()); var sentryDotNet = SentrySdk.Init(sentryUnityOptions); - SentryMonoBehaviour.Instance.ApplicationQuitting += () => + ApplicationAdapter.Instance.Quitting += () => { sentryUnityOptions.DiagnosticLogger?.LogDebug("Closing the sentry-dotnet SDK"); sentryDotNet.Dispose(); From c0acbd7c976c0fe12eb86c508c1319496ec2cbd3 Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Fri, 4 Mar 2022 11:34:44 +0100 Subject: [PATCH 3/6] feat: call native sentry close() on iOS app shutdown (if reported...) --- package-dev/Plugins/iOS/SentryNativeBridge.m | 4 ++++ src/Sentry.Unity.iOS/SentryCocoaBridgeProxy.cs | 3 +++ src/Sentry.Unity.iOS/SentryNativeIos.cs | 6 ++++++ 3 files changed, 13 insertions(+) diff --git a/package-dev/Plugins/iOS/SentryNativeBridge.m b/package-dev/Plugins/iOS/SentryNativeBridge.m index e8ee40550..8c99f796e 100644 --- a/package-dev/Plugins/iOS/SentryNativeBridge.m +++ b/package-dev/Plugins/iOS/SentryNativeBridge.m @@ -6,6 +6,10 @@ bool CrashedLastRun() { return[SentrySDK crashedLastRun]; } +void Close() { + [SentrySDK close]; +} + void SentryNativeBridgeAddBreadcrumb(const char* timestamp, const char* message, const char* type, const char* category, int level) { if (timestamp == NULL && message == NULL && type == NULL && category == NULL) { return; diff --git a/src/Sentry.Unity.iOS/SentryCocoaBridgeProxy.cs b/src/Sentry.Unity.iOS/SentryCocoaBridgeProxy.cs index f14bcc278..45cee2766 100644 --- a/src/Sentry.Unity.iOS/SentryCocoaBridgeProxy.cs +++ b/src/Sentry.Unity.iOS/SentryCocoaBridgeProxy.cs @@ -14,6 +14,9 @@ internal static class SentryCocoaBridgeProxy [DllImport("__Internal")] public static extern bool CrashedLastRun(); + [DllImport("__Internal")] + public static extern void Close(); + [DllImport("__Internal")] public static extern void SentryNativeBridgeAddBreadcrumb(string timestamp, string? message, string? type, string? category, int level); diff --git a/src/Sentry.Unity.iOS/SentryNativeIos.cs b/src/Sentry.Unity.iOS/SentryNativeIos.cs index 949a400da..32d19075f 100644 --- a/src/Sentry.Unity.iOS/SentryNativeIos.cs +++ b/src/Sentry.Unity.iOS/SentryNativeIos.cs @@ -1,4 +1,5 @@ using Sentry.Extensibility; +using Sentry.Unity.Integrations; namespace Sentry.Unity.iOS { @@ -25,6 +26,11 @@ public static void Configure(SentryUnityOptions options) return crashedLastRun; }; + ApplicationAdapter.Instance.Quitting += () => + { + options.DiagnosticLogger?.LogDebug("Closing the sentry-cocoa SDK"); + SentryCocoaBridgeProxy.Close(); + }; } } } From 81d4a05a3cea5f89275abe2b04b53ab17c1e47da Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Fri, 4 Mar 2022 11:52:41 +0100 Subject: [PATCH 4/6] feat: call native & java sentry close() on Android app shutdown (if reported...) --- src/Sentry.Unity.Android/SentryJava.cs | 6 ++++++ src/Sentry.Unity.Android/SentryNative.cs | 5 +++++ src/Sentry.Unity.Android/SentryNativeAndroid.cs | 8 ++++++++ 3 files changed, 19 insertions(+) diff --git a/src/Sentry.Unity.Android/SentryJava.cs b/src/Sentry.Unity.Android/SentryJava.cs index 4a7b44c01..73bc0ecd7 100644 --- a/src/Sentry.Unity.Android/SentryJava.cs +++ b/src/Sentry.Unity.Android/SentryJava.cs @@ -28,5 +28,11 @@ public static class SentryJava return jo.CallStatic("isCrashedLastRun") ?.Call("booleanValue"); } + + public static void Close() + { + using var jo = new AndroidJavaObject("io.sentry.Sentry"); + jo.CallStatic("close"); + } } } diff --git a/src/Sentry.Unity.Android/SentryNative.cs b/src/Sentry.Unity.Android/SentryNative.cs index 507fd4a06..a3fd9bc5c 100644 --- a/src/Sentry.Unity.Android/SentryNative.cs +++ b/src/Sentry.Unity.Android/SentryNative.cs @@ -14,6 +14,8 @@ namespace Sentry.Unity.Android /// public static class SentryNative { + public static void Close() => sentry_close(); + /// /// Re-installs the sentry-native backend essentially retaking the signal handlers. /// @@ -30,6 +32,9 @@ public static class SentryNative [DllImport("sentry")] private static extern void sentry_reinstall_backend(); + [DllImport("sentry")] + private static extern void sentry_close(); + // Testing internal static Action ReinstallSentryNativeBackendStrategy = sentry_reinstall_backend; } diff --git a/src/Sentry.Unity.Android/SentryNativeAndroid.cs b/src/Sentry.Unity.Android/SentryNativeAndroid.cs index 59ce2d952..e8c7fe588 100644 --- a/src/Sentry.Unity.Android/SentryNativeAndroid.cs +++ b/src/Sentry.Unity.Android/SentryNativeAndroid.cs @@ -1,4 +1,5 @@ using Sentry.Extensibility; +using Sentry.Unity.Integrations; namespace Sentry.Unity.Android { @@ -44,6 +45,13 @@ public static void Configure(SentryUnityOptions options, ISentryUnityInfo sentry // So we register our backend once more to make sure user-defined data is available in the crash report. SentryNative.ReinstallBackend(); } + ApplicationAdapter.Instance.Quitting += () => + { + options.DiagnosticLogger?.LogDebug("Closing the sentry-java SDK"); + SentryJava.Close(); + options.DiagnosticLogger?.LogDebug("Closing the sentry-native SDK"); + SentryNative.Close(); + }; } } } From 08e198fccb10b7ed98c4b366d5c2ceb840aa5f63 Mon Sep 17 00:00:00 2001 From: Ivan Dlugos Date: Tue, 8 Mar 2022 15:36:37 +0100 Subject: [PATCH 5/6] chore: update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a85e84ff3..95f980a9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ ### Fixes - iOS builds no longer break when native support disabled or not available ([#592](https://github.com/getsentry/sentry-unity/pull/592)) +- Close sentry instance when quitting the app ([#608](https://github.com/getsentry/sentry-unity/pull/608)) ## 0.11.0 From c1f7b14a3110bad6dd10cc54d975c23589a08983 Mon Sep 17 00:00:00 2001 From: Ivan Dlugos <6349682+vaind@users.noreply.github.com> Date: Wed, 9 Mar 2022 11:15:42 +0100 Subject: [PATCH 6/6] Update src/Sentry.Unity.Android/SentryNativeAndroid.cs Co-authored-by: Bruno Garcia --- src/Sentry.Unity.Android/SentryNative.cs | 5 ----- src/Sentry.Unity.Android/SentryNativeAndroid.cs | 3 +-- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Sentry.Unity.Android/SentryNative.cs b/src/Sentry.Unity.Android/SentryNative.cs index a3fd9bc5c..507fd4a06 100644 --- a/src/Sentry.Unity.Android/SentryNative.cs +++ b/src/Sentry.Unity.Android/SentryNative.cs @@ -14,8 +14,6 @@ namespace Sentry.Unity.Android /// public static class SentryNative { - public static void Close() => sentry_close(); - /// /// Re-installs the sentry-native backend essentially retaking the signal handlers. /// @@ -32,9 +30,6 @@ public static class SentryNative [DllImport("sentry")] private static extern void sentry_reinstall_backend(); - [DllImport("sentry")] - private static extern void sentry_close(); - // Testing internal static Action ReinstallSentryNativeBackendStrategy = sentry_reinstall_backend; } diff --git a/src/Sentry.Unity.Android/SentryNativeAndroid.cs b/src/Sentry.Unity.Android/SentryNativeAndroid.cs index e8c7fe588..4142f494f 100644 --- a/src/Sentry.Unity.Android/SentryNativeAndroid.cs +++ b/src/Sentry.Unity.Android/SentryNativeAndroid.cs @@ -47,10 +47,9 @@ public static void Configure(SentryUnityOptions options, ISentryUnityInfo sentry } ApplicationAdapter.Instance.Quitting += () => { + // Sentry Native is initialized and closed by the Java SDK, no need to call into it directly options.DiagnosticLogger?.LogDebug("Closing the sentry-java SDK"); SentryJava.Close(); - options.DiagnosticLogger?.LogDebug("Closing the sentry-native SDK"); - SentryNative.Close(); }; } }