What to do on TransactionTooLargeException

前端 未结 30 3375
盖世英雄少女心
盖世英雄少女心 2020-11-22 03:08

I got a TransactionTooLargeException. Not reproducible. In the docs it says

The Binder transaction failed because it was too large.

D

30条回答
  •  栀梦
    栀梦 (楼主)
    2020-11-22 03:44

    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.

提交回复
热议问题