TransactionTooLargeException from Samsung's SmartClip service crashing my app - can it be intercepted?

Viewed 126

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.

1 Answers

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.

Related