Skip to content

fix: Android 5 attachment issues #1652

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 24 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
972e710
attachment issues
bitsandfoxes May 14, 2024
8c4eba9
jni executor for detaching
bitsandfoxes May 14, 2024
8c81872
.
bitsandfoxes May 15, 2024
f2c3fa1
Updated CHANGELOG.md
bitsandfoxes May 15, 2024
d579725
Merge branch 'main' into fix/android-no-bueno
bitsandfoxes May 15, 2024
fbeec2f
added reusable background worker as fallback for old android
bitsandfoxes May 16, 2024
2a67c2d
Merge branch 'fix/android-no-bueno' of https://github.com/getsentry/s…
bitsandfoxes May 16, 2024
295be7b
Format code
getsentry-bot May 16, 2024
5470ec0
.
bitsandfoxes May 16, 2024
b00e3ac
Merge branch 'fix/android-no-bueno' of https://github.com/getsentry/s…
bitsandfoxes May 16, 2024
46dca64
fixed platform dependency and tests
bitsandfoxes May 17, 2024
1f922c1
properly detach
bitsandfoxes May 17, 2024
31b7f7e
comment
bitsandfoxes May 17, 2024
bc09463
Format code
getsentry-bot May 17, 2024
8b7fbf5
yeet complexity
bitsandfoxes May 17, 2024
323b144
merge
bitsandfoxes May 17, 2024
7be3763
don't touch .NET
bitsandfoxes May 17, 2024
919a2cb
Format code
getsentry-bot May 17, 2024
c492499
worker cleanup
bitsandfoxes May 17, 2024
32f6ae3
Create the JNI Executor only on a need to basis
bitsandfoxes May 17, 2024
deeff11
Create the JNI executor only on a need-to basis
bitsandfoxes May 17, 2024
e14bdbc
Update src/Sentry.Unity.Android/SentryNativeAndroid.cs
bitsandfoxes May 17, 2024
ce78387
Update src/Sentry.Unity.Android/SentryNativeAndroid.cs
bitsandfoxes May 17, 2024
67aaa6b
Format code
getsentry-bot May 17, 2024
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### Fixes

- The SDK no longer crashes on Android versions 5 and 6 with native support enabled ([#1652](https://github.com/getsentry/sentry-unity/pull/1652))

### Dependencies

- Bump Cocoa SDK from v8.25.2 to v8.26.0 ([#1648](https://github.com/getsentry/sentry-unity/pull/1648))
Expand Down
85 changes: 48 additions & 37 deletions src/Sentry.Unity.Android/AndroidJavaScopeObserver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,63 +14,74 @@ public AndroidJavaScopeObserver(SentryOptions options) : base("Android", options

public override void AddBreadcrumbImpl(Breadcrumb breadcrumb)
{
AndroidJNI.AttachCurrentThread();
using var sentry = GetSentryJava();
using var javaBreadcrumb = new AndroidJavaObject("io.sentry.Breadcrumb");
javaBreadcrumb.Set("message", breadcrumb.Message);
javaBreadcrumb.Set("type", breadcrumb.Type);
javaBreadcrumb.Set("category", breadcrumb.Category);
using var javaLevel = breadcrumb.Level.ToJavaSentryLevel();
javaBreadcrumb.Set("level", javaLevel);
sentry.CallStatic("addBreadcrumb", javaBreadcrumb, null);
SentryJniExecutor.FireAndForget(() =>
{
using var sentry = GetSentryJava();
using var javaBreadcrumb = new AndroidJavaObject("io.sentry.Breadcrumb");
javaBreadcrumb.Set("message", breadcrumb.Message);
javaBreadcrumb.Set("type", breadcrumb.Type);
javaBreadcrumb.Set("category", breadcrumb.Category);
using var javaLevel = breadcrumb.Level.ToJavaSentryLevel();
javaBreadcrumb.Set("level", javaLevel);
sentry.CallStatic("addBreadcrumb", javaBreadcrumb, null);
});
}

public override void SetExtraImpl(string key, string? value)
{
AndroidJNI.AttachCurrentThread();
using var sentry = GetSentryJava();
sentry.CallStatic("setExtra", key, value);
SentryJniExecutor.FireAndForget(() =>
{
using var sentry = GetSentryJava();
sentry.CallStatic("setExtra", key, value);
});
}
public override void SetTagImpl(string key, string value)
{
AndroidJNI.AttachCurrentThread();
using var sentry = GetSentryJava();
sentry.CallStatic("setTag", key, value);
SentryJniExecutor.FireAndForget(() =>
{
using var sentry = GetSentryJava();
sentry.CallStatic("setTag", key, value);
});
}

public override void UnsetTagImpl(string key)
{
AndroidJNI.AttachCurrentThread();
using var sentry = GetSentryJava();
sentry.CallStatic("removeTag", key);
SentryJniExecutor.FireAndForget(() =>
{
using var sentry = GetSentryJava();
sentry.CallStatic("removeTag", key);
});
}

public override void SetUserImpl(SentryUser user)
{
AndroidJNI.AttachCurrentThread();

AndroidJavaObject? javaUser = null;
try
{
javaUser = new AndroidJavaObject("io.sentry.protocol.User");
javaUser.Set("email", user.Email);
javaUser.Set("id", user.Id);
javaUser.Set("username", user.Username);
javaUser.Set("ipAddress", user.IpAddress);
using var sentry = GetSentryJava();
sentry.CallStatic("setUser", javaUser);
}
finally
SentryJniExecutor.FireAndForget(() =>
{
javaUser?.Dispose();
}
AndroidJavaObject? javaUser = null;
try
{
javaUser = new AndroidJavaObject("io.sentry.protocol.User");
javaUser.Set("email", user.Email);
javaUser.Set("id", user.Id);
javaUser.Set("username", user.Username);
javaUser.Set("ipAddress", user.IpAddress);
using var sentry = GetSentryJava();
sentry.CallStatic("setUser", javaUser);
}
finally
{
javaUser?.Dispose();
}
});
}

public override void UnsetUserImpl()
{
AndroidJNI.AttachCurrentThread();
using var sentry = GetSentryJava();
sentry.CallStatic("setUser", null);
SentryJniExecutor.FireAndForget(() =>
{
using var sentry = GetSentryJava();
sentry.CallStatic("setUser", null);
});
}
}
}
39 changes: 18 additions & 21 deletions src/Sentry.Unity.Android/SentryJava.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Threading;
using UnityEngine;

namespace Sentry.Unity.Android
Expand All @@ -15,15 +16,13 @@ internal static class SentryJava
{
internal static string? GetInstallationId()
{
if (!Attach())
return SentryJniExecutor.Run(() =>
{
return null;
}

using var sentry = GetSentryJava();
using var hub = sentry.CallStatic<AndroidJavaObject>("getCurrentHub");
using var options = hub?.Call<AndroidJavaObject>("getOptions");
return options?.Call<string>("getDistinctId");
using var sentry = GetSentryJava();
using var hub = sentry.CallStatic<AndroidJavaObject>("getCurrentHub");
using var options = hub?.Call<AndroidJavaObject>("getOptions");
return options?.Call<string>("getDistinctId");
});
}

/// <summary>
Expand All @@ -38,25 +37,23 @@ internal static class SentryJava
/// </returns>
public static bool? CrashedLastRun()
{
if (!Attach())
return SentryJniExecutor.Run(() =>
{
return null;
}
using var sentry = GetSentryJava();
using var jo = sentry.CallStatic<AndroidJavaObject>("isCrashedLastRun");
return jo?.Call<bool>("booleanValue");
using var sentry = GetSentryJava();
using var jo = sentry.CallStatic<AndroidJavaObject>("isCrashedLastRun");
return jo?.Call<bool>("booleanValue");
});
}

public static void Close()
{
if (Attach())
SentryJniExecutor.FireAndForget(() =>
{
using var sentry = GetSentryJava();
sentry.CallStatic("close");
}
});
}

private static bool Attach() => AndroidJNI.AttachCurrentThread() == 0;
private static AndroidJavaObject GetSentryJava() => new AndroidJavaClass("io.sentry.Sentry");

public static void WriteScope(
Expand All @@ -76,17 +73,17 @@ public static void WriteScope(
bool? GpuMultiThreadedRendering,
string? GpuGraphicsShaderLevel)
{
if (Attach())
SentryJniExecutor.FireAndForget(() =>
{
using var gpu = new AndroidJavaObject("io.sentry.protocol.Gpu");
gpu.SetIfNotNull("name", GpuName);
gpu.SetIfNotNull("id", GpuId);
int intVendorId;
if (GpuVendorId is not null && int.TryParse(GpuVendorId, out intVendorId) && intVendorId != 0)
if (GpuVendorId is not null && int.TryParse(GpuVendorId, out var intVendorId) && intVendorId != 0)
{
using var integer = new AndroidJavaObject("java.lang.Integer", intVendorId);
gpu.Set("vendorId", integer);
}

gpu.SetIfNotNull("vendorName", GpuVendorName);
gpu.SetIfNotNull("memorySize", GpuMemorySize);
gpu.SetIfNotNull("apiType", GpuApiType);
Expand All @@ -100,7 +97,7 @@ public static void WriteScope(
using var contexts = scope.Call<AndroidJavaObject>("getContexts");
contexts.Call("setGpu", gpu);
}));
}
});
}

private static void SetIfNotNull<T>(this AndroidJavaObject javaObject, string property, T? value, string? valueClass = null)
Expand Down
77 changes: 77 additions & 0 deletions src/Sentry.Unity.Android/SentryJniExecutor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System;
using System.Threading;
using UnityEngine;

namespace Sentry.Unity.Android
{
internal static class SentryJniExecutor
{
public static TResult? Run<TResult>(Func<TResult?> jniOperation)
{
TResult? result = default;
Exception? exception = null;

var thread = new Thread(() =>
{
if (AndroidJNI.AttachCurrentThread() != 0)
{
exception = new InvalidOperationException("Failed to attach thread to JVM");
return;
}

try
{
result = jniOperation();
}
finally
{
AndroidJNI.DetachCurrentThread();
}
});

thread.Start();
thread.Join();

if (exception is not null)
{
// Adding the Sentry logger tag ensures we don't send this error to Sentry.
Debug.unityLogger.Log(LogType.Exception, UnityLogger.LogTag, $"Error during JNI execution: {exception}");
}

return result;
}

public static void FireAndForget(Action jniOperation)
{
Exception? exception = null;

new Thread(() =>
{
if (AndroidJNI.AttachCurrentThread() != 0)
{
exception = new InvalidOperationException("Failed to attach thread to JVM");
return;
}

try
{
jniOperation();
}
catch (Exception ex)
{
exception = ex;
}
finally
{
AndroidJNI.DetachCurrentThread();
}
}).Start();

if (exception is not null)
{
// Adding the Sentry logger tag ensures we don't send this error to Sentry.
Debug.unityLogger.Log(LogType.Exception, UnityLogger.LogTag, $"Error during JNI execution: {exception}");
}
}
}
}
Loading