Skip to content
Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Fixes

- The SDK no longer sends events when it fails to initialize the native SDK on Windows and Linux and logs those instead. It also suppresses `EntryPointNotFoundException` if sentry-native is not available at runtime. Native crashes won't get capture but it'll continue to capture C# errors. ([#1898](https://github.com/getsentry/sentry-unity/pull/1898))
- The SDK no longer closes the underlying native SDK during the games shutdown if native support has not been enabled. This allows the SDK to support and capture errors in case of building the game as a library on a mobile (Android or iOS) game. ([#1897](https://github.com/getsentry/sentry-unity/pull/1897))

### Dependencies
Expand Down
20 changes: 2 additions & 18 deletions package-dev/Runtime/SentryInitialization.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ public static void Init()
if (options != null && options.ShouldInitializeSdk())
{
SentryIntegrations.Configure(options);
Exception nativeInitException = null;

try
{
Expand All @@ -76,20 +75,16 @@ public static void Init()
}
catch (DllNotFoundException e)
{
nativeInitException = new Exception(
options.DiagnosticLogger?.LogError(
"Sentry native-error capture configuration failed to load a native library. This usually " +
"means the library is missing from the application bundle or the installation directory.", e);
}
catch (Exception e)
{
nativeInitException = new Exception("Sentry native error capture configuration failed.", e);
options.DiagnosticLogger?.LogError("Sentry native error capture configuration failed.", e);
}

SentryUnity.Init(options);
if (nativeInitException != null)
{
SentrySdk.CaptureException(nativeInitException);
}

#if !SENTRY_WEBGL
if (options.TracesSampleRate > 0.0f && options.AutoStartupTraces)
Expand Down Expand Up @@ -118,17 +113,6 @@ public static void Init()
#endif
}
}

#if SENTRY_NATIVE
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
public static void ReinstallBackend()
{
// At this point Unity has taken the signal handler and will not invoke our handler. So we register our
// backend once more to make sure user-defined data is available in the crash report and the SDK is able
// to capture the crash.
SentryNative.ReinstallBackend();
}
#endif
}

public class SentryUnityInfo : ISentryUnityInfo
Expand Down
49 changes: 42 additions & 7 deletions src/Sentry.Unity.Native/SentryNative.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Sentry.Extensibility;
using Sentry.Unity.Integrations;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Analytics;

namespace Sentry.Unity.Native;
Expand All @@ -13,40 +14,45 @@ public static class SentryNative
{
private static readonly Dictionary<string, bool> PerDirectoryCrashInfo = new();

private static bool ShouldReinstallBackend;
private static IDiagnosticLogger? Logger;

/// <summary>
/// Configures the native SDK.
/// </summary>
/// <param name="options">The Sentry Unity options to use.</param>
/// <param name="sentryUnityInfo">Infos about the current Unity environment</param>
public static void Configure(SentryUnityOptions options, ISentryUnityInfo sentryUnityInfo)
{
options.DiagnosticLogger?.LogInfo("Attempting to configure native support via the Native SDK");
Logger = options.DiagnosticLogger;

Logger?.LogInfo("Attempting to configure native support via the Native SDK");

if (!sentryUnityInfo.IsNativeSupportEnabled(options, ApplicationAdapter.Instance.Platform))
{
options.DiagnosticLogger?.LogDebug("Native support is disabled for '{0}'.", ApplicationAdapter.Instance.Platform);
Logger?.LogDebug("Native support is disabled for '{0}'.", ApplicationAdapter.Instance.Platform);
return;
}

try
{
if (!SentryNativeBridge.Init(options, sentryUnityInfo))
{
options.DiagnosticLogger?
Logger?
.LogWarning("Sentry native initialization failed - native crashes are not captured.");
return;
}
}
catch (Exception e)
{
options.DiagnosticLogger?
Logger?
.LogError(e, "Sentry native initialization failed - native crashes are not captured.");
return;
}

ApplicationAdapter.Instance.Quitting += () =>
{
options.DiagnosticLogger?.LogDebug("Closing the sentry-native SDK");
Logger?.LogDebug("Closing the sentry-native SDK");
SentryNativeBridge.Close();
};
options.ScopeObserver = new NativeScopeObserver(options);
Expand Down Expand Up @@ -75,12 +81,41 @@ public static void Configure(SentryUnityOptions options, ISentryUnityInfo sentry
crashedLastRun = SentryNativeBridge.HandleCrashedLastRun(options);
PerDirectoryCrashInfo.Add(cacheDirectory, crashedLastRun);

options.DiagnosticLogger?
Logger?
.LogDebug("Native SDK reported: 'crashedLastRun': '{0}'", crashedLastRun);
}
}
options.CrashedLastRun = () => crashedLastRun;

ShouldReinstallBackend = true;
}

public static void ReinstallBackend() => SentryNativeBridge.ReinstallBackend();
// We're calling this in `BeforeSceneLoad` instead of `SubsystemRegistration` as it's too soon and the
// SignalHandler would still get overwritten.
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could have had this in here all along? :)
I dont' recall why we left on SentryInitialization originally, do you recall?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The intention was to have everything annotated RuntimeInitializeOnLoadMethod in the SentryInitialization.cs so users could overwrite/remove it. But it should have belonged in SentryNative all along.

private static void ReinstallBackend()
{
// The backend should only be reinstalled if the native SDK has been initialized successfully.
if (!ShouldReinstallBackend)
{
Logger?.LogWarning("Skipping reinstalling the native backend.");
return;
}
else
{
Logger?.LogDebug("Reinstalling the native backend to make sure we capture native crashes.");
}

try
{
// At this point Unity has taken the signal handler and will not invoke our handler. So we register our
// backend once more to make sure user-defined data is available in the crash report and the SDK is able
// to capture the crash.
SentryNativeBridge.ReinstallBackend();
}
catch (EntryPointNotFoundException e)
{
Logger?.LogError(e, "Native dependency not found. Did you delete sentry.dll or move files around?");
}
}
}