What to do on TransactionTooLargeException

2018-12-31 09:36发布

I got in error track of an app TransactionTooLargeException. Not reproducible and never had it before. In the docs it says

The Binder transaction failed because it was too large.

During a remote procedure call, the arguments and the return value of the call are transferred as Parcel objects stored in the Binder transaction buffer. If the arguments or the return value are too large to fit in the transaction buffer, then the call will fail and TransactionTooLargeException will be thrown.

...

There are two possible outcomes when a remote procedure call throws TransactionTooLargeException. Either the client was unable to send its request to the service (most likely if the arguments were too large to fit in the transaction buffer), or the service was unable to send its response back to the client (most likely if the return value was too large to fit in the transaction buffer).

...

So, ok, somewhere I'm passing or receiving arguments which exceed some unknown limit. But where?

The stacktrace doesn't show anything from my files:

java.lang.RuntimeException: Adding window failed
at android.view.ViewRootImpl.setView(ViewRootImpl.java:548)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:406)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:320)
at android.view.WindowManagerImpl$CompatModeWrapper.addView(WindowManagerImpl.java:152)
at android.view.Window$LocalWindowManager.addView(Window.java:557)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2897)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
at android.app.ActivityThread.access$600(ActivityThread.java:139)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1262)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:4977)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)
Caused by: android.os.TransactionTooLargeException
at android.os.BinderProxy.transact(Native Method)
at android.view.IWindowSession$Stub$Proxy.add(IWindowSession.java:569)
at android.view.ViewRootImpl.setView(ViewRootImpl.java:538)
... 16 more
android.os.TransactionTooLargeException
at android.os.BinderProxy.transact(Native Method)
at android.view.IWindowSession$Stub$Proxy.add(IWindowSession.java:569)
at android.view.ViewRootImpl.setView(ViewRootImpl.java:538)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:406)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:320)
at android.view.WindowManagerImpl$CompatModeWrapper.addView(WindowManagerImpl.java:152)
at android.view.Window$LocalWindowManager.addView(Window.java:557)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2897)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
at android.app.ActivityThread.access$600(ActivityThread.java:139)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1262)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:4977)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)

It seems to be related with views, because all the Window / View lines? How is this related to remote procedure call? How can I look for the reason of this error?

In the app I'm using only Webservices, I'm not using Service class, are the Webservices the "remote procedure calls" or what else could be...?

P.S. Maybe it's important: Android version: 4.0.3, Device: HTC One X

30条回答
爱死公子算了
2楼-- · 2018-12-31 10:02

As Intents, Content Providers, Messenger, all system services like Telephone, Vibrator etc. utilize IPC infrastructure provider by Binder.Moreover the activity lifecycle callbacks also use this infrastructure.

1MB is the overall limit on all the binder transactions executed in the system at a particular moment.

In case there are lot of transactions happening when the intent is sent,it may fail even though extra data is not large. http://codetheory.in/an-overview-of-android-binder-framework/

查看更多
十年一品温如言
3楼-- · 2018-12-31 10:03

Make sure that you do not put into Intent object data of large size. In my case I was adding String 500k size and then starting another activity. It always failed with this exception. I avoided sharing data between activities by using static variables of activities - you don't have to send them to Intent and then pulling from it.

What I had:

String html = new String();//some string of 500K data.
Intent intent = new Intent(MainActivity.this, PageWebView.class);
//this is workaround - I just set static variable and then access it from another    activity.
MainActivity.htmlBody = timelineDb.getHTMLBodyForTweet(tweet);
//This line was present and it actually failed with the same exception you had.
//intent.putExtra("com.gladimdim.offtie.webview", html);
查看更多
怪性笑人.
4楼-- · 2018-12-31 10:03

This one line of code in writeToParcel(Parcel dest, int flags) method helped me to get rid of TransactionTooLargeException.

dest=Parcel.obtain(); 

After this code only i am writing all data to the parcel object i.e dest.writeInt() etc.

查看更多
闭嘴吧你
5楼-- · 2018-12-31 10:04

This is not a definitive answer, but it may shed some light on the causes of a TransactionTooLargeException and help pinpoint the problem.

Although most answers refer to large amounts of data transferred, I see this exception being thrown incidentally after heavy scrolling and zooming and repeatedly opening an ActionBar spinner menu. The crash happens on tapping the action bar. (this is a custom mapping app)

The only data being passed around seem to be touches from the "Input Dispatcher" to the app. I think this cannot reasonably amount to anywhere near 1 mb in the "Transaction Buffer".

My app is running on a quad core 1.6 GHz device and uses 3 threads for heavylifting, keeping one core free for the UI thread. Furthermore, the app uses android:largeHeap, has 10 mb of unused heap left and has 100 mb of room left to grow the heap. So I wouldn't say it is a resource issue.

The crash is always immediately preceded by these lines:

W/InputDispatcher( 2271): channel ~ Consumer closed input channel or an error occurred.  events=0x9
E/InputDispatcher( 2271): channel ~ Channel is unrecoverably broken and will be disposed!
E/JavaBinder(28182): !!! FAILED BINDER TRANSACTION !!!

Which are not neccesarily printed in that order, but (as far as I checked) happen on the same millisecond.

And the stack trace itself, for clarity, is the same as in the question:

E/AndroidRuntime(28182): java.lang.RuntimeException: Adding window failed
..
E/AndroidRuntime(28182): Caused by: android.os.TransactionTooLargeException

Delving into the source code of android one finds these lines:

frameworks/base/core/jni/android_util_Binder.cpp:

case FAILED_TRANSACTION:
    ALOGE("!!! FAILED BINDER TRANSACTION !!!");
    // TransactionTooLargeException is a checked exception, only throw from certain methods.
    // FIXME: Transaction too large is the most common reason for FAILED_TRANSACTION
    //        but it is not the only one.  The Binder driver can return BR_FAILED_REPLY
    //        for other reasons also, such as if the transaction is malformed or
    //        refers to an FD that has been closed.  We should change the driver
    //        to enable us to distinguish these cases in the future.
    jniThrowException(env, canThrowRemoteException
            ? "android/os/TransactionTooLargeException"
                    : "java/lang/RuntimeException", NULL);

To me it sounds like I'm possibly hitting this undocumented feature, where the transaction fails for other reasons than a Transaction being TooLarge. They should have named it TransactionTooLargeOrAnotherReasonException.

At this time I did not solve the issue, but if I find something useful I will update this answer.

update: it turned out my code leaked some file descriptors, the number of which is maximized in linux (typically 1024), and this seems to have triggered the exception. So it was a resource issue after all. I verified this by opening /dev/zero 1024 times, which resulted in all kinds of weird exceptions in UI related actions, including the exception above, and even some SIGSEGV's. Apparently failure to open a file/socket is not something which is handled/reported very cleanly throughout Android.

查看更多
一个人的天荒地老
6楼-- · 2018-12-31 10:04

I got a TransactionTooLargeException from a Stackoverflow error in a Android Espresso test. I found the stackoverflow error stack trace in the logs when I took off the Logcat filter for my app.

I'm guessing that Espresso caused the TransactionTooLargeException when trying to handle a really large exception stacktrace.

查看更多
无与为乐者.
7楼-- · 2018-12-31 10:05

When I am dealing with the WebView in my app it happens. I think it's related to addView and UI resources. In my app I add some code in WebViewActivity like this below then it runs ok:

@Override
protected void onDestroy() {
    if (mWebView != null) {
        ((ViewGroup) mWebView.getParent()).removeView(mWebView);  
        mWebView.removeAllViews();  
        mWebView.destroy();
    }
    super.onDestroy();
}
查看更多
登录 后发表回答