Skip to content

fix(android): Avoid using AndroidJavaObject from background threads #161

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 1 commit into from
Aug 20, 2019
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

### Bug fixes

* (Android) Disable reporting for crashes on background threads on x86 devices
[#161](https://github.com/bugsnag/bugsnag-unity/pull/161)
* (Android) Discard duplicate reports for C/C++ exceptions reporting when Unity
Cloud Diagnostics is enabled

Expand Down
47 changes: 46 additions & 1 deletion src/BugsnagUnity/Native/Android/NativeInterface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Runtime.InteropServices;
using BugsnagUnity.Payload;
using UnityEngine;
using System.Threading;

namespace BugsnagUnity
{
Expand Down Expand Up @@ -34,8 +35,17 @@ class NativeInterface
private IntPtr ObjectGetClass;
private IntPtr ObjectToString;

private bool CanRunOnBackgroundThread;
private Thread MainThread;

public NativeInterface(AndroidJavaObject config)
{
MainThread = Thread.CurrentThread;
using (var system = new AndroidJavaClass("java.lang.System"))
{
var arch = system.CallStatic<string>("getProperty", "os.arch");
CanRunOnBackgroundThread = (arch != "x86" && arch != "i686" && arch != "x86_64");
}
using (var unityPlayerClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
using (var activity = unityPlayerClass.GetStatic<AndroidJavaObject>("currentActivity"))
using (var context = activity.Call<AndroidJavaObject>("getApplicationContext"))
Expand Down Expand Up @@ -158,6 +168,9 @@ public void SetAppVersion(string newValue) {
}

public void SetNotifyReleaseStages(string[] stages) {
if (!CanRunJNI()) {
return;
}
bool isAttached = bsg_unity_isJNIAttached();
if (!isAttached) {
AndroidJNI.AttachCurrentThread();
Expand Down Expand Up @@ -226,6 +239,9 @@ public void AddToTab(string tab, string key, string value) {
}

public void LeaveBreadcrumb(string name, string type, IDictionary<string, string> metadata) {
if (!CanRunJNI()) {
return;
}
bool isAttached = bsg_unity_isJNIAttached();
if (!isAttached) {
AndroidJNI.AttachCurrentThread();
Expand All @@ -240,6 +256,9 @@ public void LeaveBreadcrumb(string name, string type, IDictionary<string, string
}

public string[] GetNotifyReleaseStages() {
if (!CanRunJNI()) {
return new string[]{};
}
bool isAttached = bsg_unity_isJNIAttached();
if (!isAttached) {
AndroidJNI.AttachCurrentThread();
Expand All @@ -258,12 +277,15 @@ public string[] GetNotifyReleaseStages() {

public List<Breadcrumb> GetBreadcrumbs()
{
List<Breadcrumb> breadcrumbs = new List<Breadcrumb>();
if (!CanRunJNI()) {
return breadcrumbs;
}
bool isAttached = bsg_unity_isJNIAttached();
if (!isAttached) {
AndroidJNI.AttachCurrentThread();
}

List<Breadcrumb> breadcrumbs = new List<Breadcrumb>();

var javaBreadcrumbs = CallNativeObjectMethod("getBreadcrumbs", "()Ljava/util/List;", new object[]{});
var iterator = AndroidJNI.CallObjectMethod(javaBreadcrumbs, CollectionIterator, new jvalue[]{});
Expand All @@ -286,6 +308,9 @@ public List<Breadcrumb> GetBreadcrumbs()

private void CallNativeVoidMethod(string methodName, string methodSig, object[] args)
{
if (!CanRunJNI()) {
return;
}
bool isAttached = bsg_unity_isJNIAttached();
if (!isAttached) {
AndroidJNI.AttachCurrentThread();
Expand All @@ -302,15 +327,28 @@ private void CallNativeVoidMethod(string methodName, string methodSig, object[]

private IntPtr CallNativeObjectMethod(string methodName, string methodSig, object[] args)
{
if (!CanRunJNI()) {
return IntPtr.Zero;
}
bool isAttached = bsg_unity_isJNIAttached();
if (!isAttached) {
AndroidJNI.AttachCurrentThread();
}
var jargs = AndroidJNIHelper.CreateJNIArgArray(args);
var methodID = AndroidJNI.GetStaticMethodID(BugsnagNativeInterface, methodName, methodSig);
var nativeValue = AndroidJNI.CallStaticObjectMethod(BugsnagNativeInterface, methodID, jargs);
AndroidJNIHelper.DeleteJNIArgArray(args, jargs);
if (!isAttached) {
AndroidJNI.DetachCurrentThread();
}
return nativeValue;
}

private string CallNativeStringMethod(string methodName, string methodSig, object[] args)
{
if (!CanRunJNI()) {
return "";
}
bool isAttached = bsg_unity_isJNIAttached();
if (!isAttached) {
AndroidJNI.AttachCurrentThread();
Expand All @@ -330,6 +368,9 @@ private string CallNativeStringMethod(string methodName, string methodSig, objec
}

private Dictionary<string, object> GetJavaMapData(string methodName) {
if (!CanRunJNI()) {
return new Dictionary<string, object>();
}
bool isAttached = bsg_unity_isJNIAttached();
if (!isAttached) {
AndroidJNI.AttachCurrentThread();
Expand Down Expand Up @@ -397,6 +438,10 @@ private AndroidJavaObject JavaMapFromDictionary(IDictionary<string, string> src)
return map;
}

private bool CanRunJNI() {
return CanRunOnBackgroundThread || object.ReferenceEquals(Thread.CurrentThread, MainThread);
}

private Dictionary<string, object> DictionaryFromJavaMap(IntPtr source) {
var dict = new Dictionary<string, object>();

Expand Down