Skip to content
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

Suspiciously short list of threads when recording ANRError as Crashlytics non-fatal exception #58

Closed
AntonPetrov83 opened this issue Jan 4, 2022 · 7 comments

Comments

@AntonPetrov83
Copy link

AntonPetrov83 commented Jan 4, 2022

Hi!

I integrated ANR-WatchDog to a Unity game using custom implementation of UnityPlayerActivity.

At first I released a game with the default behaviour of the ANR-WatchDog.
My app crashed due to unhandled ANRError and Firebase Crashlytics recorded something around 40 threads at this moment including UnityMain thread and others. I used setReportMainThreadOnly() because Crashlytics collects all threads by itself on fatal errors.

Then I turned this crash to a non-fatal using this code:

    @Override protected void onCreate(Bundle savedInstanceState)
    {
        ANRWatchDog watchDog = new ANRWatchDog();
        watchDog.setANRListener(new ANRWatchDog.ANRListener() {
            @Override
            public void onAppNotResponding(ANRError error) {
                FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance();
                crashlytics.recordException(error);
            }
        });
        watchDog.start();

        super.onCreate(savedInstanceState);
    }

This code records ANRError as a non-fatal exception and Crashlytics attaches stack traces contained in ANRError. That is why you do not see setReportMainThreadOnly() here any more. But now crash reports a very short, containing only 8-10 threads. What is strange there were no UnityMain thread while this non-fatal was triggered in the middle of a gameplay.

Please help, any ideas on how to get full list of stack traces attached?

@AntonPetrov83 AntonPetrov83 changed the title Suspiciously short list of threads when using setANRListener Suspiciously short list of threads when recording ANRError as Crashlytics non-fatal exception Jan 4, 2022
@AntonPetrov83
Copy link
Author

Okay, this is by design :(

Under the hood Crashlytics trims stack-traces longer then 1024 entries. ANRError collects all thread stacks as a single long stack-trace and it gets trimmed by Crashlytics.

So the solution is either crash with Fatal error to allow Crashlytics collect all threads or collect threads by ourselves and send it somewhere.

@mastef
Copy link

mastef commented Feb 15, 2022

@AntonPetrov83 unrelated but would be cool if you could share your solution on how to use ANR-WatchDog with unity. Lots of people have now ANR issues since recently

@AntonPetrov83
Copy link
Author

@AntonPetrov83 unrelated but would be cool if you could share your solution on how to use ANR-WatchDog with unity. Lots of people have now ANR issues since recently

@mastef create a derived class from UnityPlayerActivity like described here: Extending the UnityPlayerActivity Java Code

Then write something like that:

    @Override protected void onCreate(Bundle savedInstanceState)
    {
        ANRWatchDog watchDog = new ANRWatchDog();
        watchDog.setReportMainThreadOnly();
        watchDog.start();

        super.onCreate(savedInstanceState);
    }

@mastef
Copy link

mastef commented Feb 16, 2022

@AntonPetrov83 unrelated but would be cool if you could share your solution on how to use ANR-WatchDog with unity. Lots of people have now ANR issues since recently

@mastef create a derived class from UnityPlayerActivity like described here: Extending the UnityPlayerActivity Java Code

Then write something like that:

    @Override protected void onCreate(Bundle savedInstanceState)
    {
        ANRWatchDog watchDog = new ANRWatchDog();
        watchDog.setReportMainThreadOnly();
        watchDog.start();

        super.onCreate(savedInstanceState);
    }

Got there after writing the comment. But the setReportMainThreadOnly is interesting! Thank you for the hint!

@mastef
Copy link

mastef commented Feb 17, 2022

@AntonPetrov83 Thanks for the help! For future reference I'm adding the code here. Unfortunately I'm not able to trigger ANRs from Unity.

package com.mycompany.gamepackage;

import com.github.anrwatchdog.ANRError;
import com.github.anrwatchdog.ANRWatchDog;
import com.github.anrwatchdog.ANRWatchDog.ANRListener;
import com.unity3d.player.UnityPlayerActivity;

import android.os.Bundle;
import android.util.Log;

public class GameActivity extends UnityPlayerActivity
{

    // Setup activity layout
    @Override protected void onCreate(Bundle savedInstanceState)
    {
        Log.d("GameActivity", "WatchDog starting");
        new ANRWatchDog(3000)
            .setIgnoreDebugger(true)
            .setReportMainThreadOnly()
            .setANRListener(new ANRWatchDog.ANRListener() {
                @Override
                public void onAppNotResponding(ANRError error) {
                    Log.e("GameActivity", "", error);
                    Log.d("GameActivity", "ANR Caught");
                }
            })
            .start();

        Log.d("GameActivity", "WatchDog started");
        super.onCreate(savedInstanceState);
    }
}

This is confirmed working.

Inside the Unity game loop I tried delaying stuff with System.Threading.Thread.Sleep(6000); but to no avail. Nothing gets triggered. Maybe blocking the Unity game loop does not cause ANRs?

@AntonPetrov83
Copy link
Author

Inside the Unity game loop I tried delaying stuff with System.Threading.Thread.Sleep(6000); but to no avail. Nothing gets triggered. Maybe blocking the Unity game loop does not cause ANRs?

Yeah, ANR triggers only when main thread is blocked and Unity runs on Unity-Main thread which is not main ))
To emulate an ANR you can use code:

public class AndroidShowStopper : MonoBehaviour
{
    private static bool _stop;

    public static void Stop()
    {
        _stop = true;
    }
    
#if UNITY_ANDROID
    void Update()
    {
        if (_stop)
        {
            AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
            AndroidJavaObject activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
            activity.Call("runOnUiThread", new AndroidJavaRunnable(runOnUiThread));
            
            _stop= false;
        }
    }

    void runOnUiThread()
    {
        Debug.Log("I'm running on the Java UI thread!");

        while (true);
    }
#endif
}

Just call AndroidShowStopper.Stop(); somewhere.

@WaheedRashad
Copy link

Hi!

I integrated ANR-WatchDog to a Unity game using custom implementation of UnityPlayerActivity.

At first I released a game with the default behaviour of the ANR-WatchDog. My app crashed due to unhandled ANRError and Firebase Crashlytics recorded something around 40 threads at this moment including UnityMain thread and others. I used setReportMainThreadOnly() because Crashlytics collects all threads by itself on fatal errors.

Then I turned this crash to a non-fatal using this code:

    @Override protected void onCreate(Bundle savedInstanceState)
    {
        ANRWatchDog watchDog = new ANRWatchDog();
        watchDog.setANRListener(new ANRWatchDog.ANRListener() {
            @Override
            public void onAppNotResponding(ANRError error) {
                FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance();
                crashlytics.recordException(error);
            }
        });
        watchDog.start();

        super.onCreate(savedInstanceState);
    }

This code records ANRError as a non-fatal exception and Crashlytics attaches stack traces contained in ANRError. That is why you do not see setReportMainThreadOnly() here any more. But now crash reports a very short, containing only 8-10 threads. What is strange there were no UnityMain thread while this non-fatal was triggered in the middle of a gameplay.

Please help, any ideas on how to get full list of stack traces attached?

How to integrate ANR-WatchDog to a Unity game using custom implementation of UnityPlayerActivity?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants