2

Android Samsung phones have a SmartClip service that is invoked when a screenshot is taken. It launches an interface to immediately allow the screenshot to be edited.

My app will often crash when this action is performed, specifically when a large number of objects are drawn on the screen. This is a Xamarin.Forms app.

When the crash occurs, two threads are reported as responsible, with the following stack traces:

android.os.BinderProxy.transactNative BinderProxy.java
android.os.BinderProxy.transact BinderProxy.java:605
com.samsung.android.content.smartclip.ISpenGestureService$Stub$Proxy.sendSmartClipRemoteRequestResult ISpenGestureService.java:910
com.samsung.android.content.smartclip.SpenGestureManager.sendSmartClipRemoteRequestResult SpenGestureManager.java:77
com.samsung.android.content.smartclip.SmartClipRemoteRequestDispatcher.sendResult SmartClipRemoteRequestDispatcher.java:654
com.samsung.android.content.smartclip.SmartClipRemoteRequestDispatcher.dispatchScrollableAreaInfo SmartClipRemoteRequestDispatcher.java:313
com.samsung.android.content.smartclip.SmartClipRemoteRequestDispatcher.access$100 SmartClipRemoteRequestDispatcher.java:59
com.samsung.android.content.smartclip.SmartClipRemoteRequestDispatcher$2.run SmartClipRemoteRequestDispatcher.java:154
android.os.Handler.handleCallback Handler.java:938
android.os.Handler.dispatchMessage Handler.java:99
android.os.Looper.loop Looper.java:246
android.app.ActivityThread.main ActivityThread.java:8512
java.lang.reflect.Method.invoke Method.java
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run RuntimeInit.java:602
com.android.internal.os.ZygoteInit.main ZygoteInit.java:1130

com.samsung.android.content.smartclip.SpenGestureManager.sendSmartClipRemoteRequestResult SpenGestureManager.java:81
com.samsung.android.content.smartclip.SmartClipRemoteRequestDispatcher.sendResult SmartClipRemoteRequestDispatcher.java:654
com.samsung.android.content.smartclip.SmartClipRemoteRequestDispatcher.dispatchScrollableAreaInfo SmartClipRemoteRequestDispatcher.java:313
com.samsung.android.content.smartclip.SmartClipRemoteRequestDispatcher.access$100 SmartClipRemoteRequestDispatcher.java:59
com.samsung.android.content.smartclip.SmartClipRemoteRequestDispatcher$2.run SmartClipRemoteRequestDispatcher.java:154
android.os.Handler.handleCallback Handler.java:938
android.os.Handler.dispatchMessage Handler.java:99
android.os.Looper.loop Looper.java:246
android.app.ActivityThread.main ActivityThread.java:8512
java.lang.reflect.Method.invoke Method.java
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run RuntimeInit.java:602
com.android.internal.os.ZygoteInit.main ZygoteInit.java:1130

So... what do I do? This is a crash originating in third party code that I'm not including myself. Is there a hook somewhere that I can prevent this action from executing, or to handle the exception without crashing my app?

The only other solution would be to reduce the number of objects displayed so it comes under the 1 Mb limit, but I'd like to avoid that.

EDIT to add: Unfortunately, it looks like UnhandledException handling is not going to suffice, it was only meant for logging information about the crash.

Nick Bauer
  • 1,027
  • 8
  • 13
  • 1
    Does this answer your question? [Global Exception Handling in Xamarin Cross platform](https://stackoverflow.com/questions/39503390/global-exception-handling-in-xamarin-cross-platform) – ToolmakerSteve Jul 30 '21 at 11:37
  • 1
    If a global exception handler doesn't catch it, then research options for native android apps. E.g. [Handle App Crash](https://stackoverflow.com/questions/27829955/android-handle-application-crash-and-start-a-particular-activity) -or- [Hide your crashes gracefully](https://stackoverflow.com/q/27829955/199364) – ToolmakerSteve Jul 30 '21 at 11:47
  • I appreciate the comments. It sounds like it isn't possible; these methods are meant to allow logging of a crash, but that's about it. So the other part of my question stands, whether there's a way to stop this code from being executed. – Nick Bauer Jul 31 '21 at 14:18
  • 1
    Maybe. Depends whether it crashes the Activity itself (or its ActivityThread). If not, then you should be able to catch the exception, and do nothing (or log it). Worst case, you might be able to restart the Activity. Obviously that's less than ideal, but its better than simply crashing. Its worth trying. – ToolmakerSteve Jul 31 '21 at 15:58
  • Hmm, I'll try that out. – Nick Bauer Jul 31 '21 at 16:00
  • I tried Thread.DefaultUncaughtExceptionHandler, which prevents a crash... but you can't do anything else, the app is frozen. CurrentDomainOnUnhandledException allows the exception to be observed and logged, but cannot stop a crash. TaskSchedulerOnUnobservedTaskException doesn't get called. – Nick Bauer Aug 03 '21 at 03:16
  • 1
    Can you read values from your main activity? write to a file? Idea is to save state, then restart main activity. Activity looks for recovery file, uses that to get back to where user was, if possible. (Then delete recovery file, so doesn't get used if user manually kills/restarts app later.) – ToolmakerSteve Aug 03 '21 at 09:48

1 Answers1

1

Thanks to @ToolmakerSteve I have a workaround.

I used the information in the links to detect this exception and restart the activity:

# in MainApplication.cs
private void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            if ((e.ExceptionObject as RuntimeException)?.InnerException is TransactionTooLargeException)
            {
                Intent intent = new Intent(ApplicationContext, typeof(MainActivity));
                intent.AddFlags(ActivityFlags.NewTask);
                StartActivity(intent);
            }
        }
    }

Trying to do any state-saving action in this method fails. You have to rely on state that's saved prior to the crash. Luckily I already had such a mechanism.

So I just needed to detect a crash on startup (I used AppCenter's Crashes.HasCrashedInLastSessionAsync() and run my state-restoring method. Though for some reason I could only run this check after populating MainPage. Doing it before risked a blank screen.

In addition to this, I implemented limits on the number of objects drawn on the screen, so that the crash happens less frequently.

This isn't the best answer because it would be better to stop the third party code from crashing apps, but I hope it helps someone else.

Nick Bauer
  • 1,027
  • 8
  • 13