Android: Handling TransactionTooLargeException

Leo N
4 min readJul 30, 2019

Why it crash?

Accordingly to Android Document,

We recommend that you keep saved state to less than 50k of data.

Note: In Android 7.0 (API level 24) and higher, the system throws a TransactionTooLargeException as a runtime exception. In lower versions of Android, the system only shows a warning in logcat.

Though it mentioned the size here, the actual calculation of the size is not easy, and hence replicating the issue is hard.

TransactionTooLargeException?

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).

More Detail

I encountered this issue, and I found that when there huge amount of data getting exchanged between a service and an application,(This involves transferring lots of thumbnails). Actually data size was around 500kb, and the IPC transaction buffer size is set to 1024KB. I am not sure why it exceeded the transaction buffer.

This also can occur, when you pass lot of data through intent extras

When you get this exception in your application, please analyze your code.

  1. Are you exchanging lot of data between your services and application?
  2. Using intents to share huge data, (for example, the user selects huge number of files from gallery share press share, the URIs of the selected files will be transferred using intents)
  3. receiving bitmap files from service
  4. waiting for android to respond back with huge data (for example, getInstalledApplications() when the user installed lot of applications)
  5. using applyBatch() with lot of operations pending

How to handle when you get this exception

If possible, split the big operation in to small chunks, for example, instead of calling applyBatch() with 1000 operations, call it with 100 each.

Do not exchange huge data (>1MB) between services and application

I dont know how to do this, but, Do not query android, which can return huge data :-)

The Binder framework is a fascinating topic that gets to the core of how Android works (and has a history stretching back to Palm OS) but I’ll summarize a few relevant details here:

  • Binder IPC allows communication to occur synchronously in each process via a “transact” method. These “Binder transactions” pass data between the processes via highly optimized data containers called Parcel.
  • Several familiar Android objects like Intent, Bundle, and Parcelable are ultimately packaged in Parcel objects in order to communicate with system_process.
  • Creating / starting / stopping / pausing / resuming / etc. an Android Activity all involve making Binder transactions.
  • Each app process has a 1 MB buffer for all Binder transactions.

Testing

If you search the internet for the exact size limit (in bytes) of data that can be added to an Intent, you will find different statements ranging from 90Kb up to 1Mb but what is the exact limit? I decided to take the test and find the limit myself. I did a binary search to find the maximum amount of bytes that didn't cause a TransactionTooLargeException or some other exception.

Results

  • API 23: 517716 bytes (520107 bytes incl. overhead);
  • API 22: 517876 bytes;
  • API 19: 518368 bytes;
  • API 16: 518396 bytes;
  • API 10: 518580 bytes;

Conclusion

The statements that Intents could transfer up to 1Mb worth of data are definitely wrong, 500Kb is more accurate. It also seems that the maximum amount decreases slightly per Android version, this has probably something to do with the addition of new features to the Intent or derived classes. My advice is to only add very basic arguments to an Intent, if you need to transfer more, you are left with the following options:

  • Store the data in a (temporary) file and pass around the file URI. This option is probably your only option if you want to transfer large amounts of data to a completely different app.
  • Store the data in the Application instance;
  • Create a singleton container holding the data you pass around.

Note: always check for null pointers
The last two options have a downside: If Android kills your app and thus the Activity stack you lose the data stored in both the singleton containers (the VM is killed) and the Application instance. If Android later restarts the Activities your app was displaying you might expect your singleton data to exist but it actually doesn’t. So you must check if you data exists, don’t assume it does.

Solution

1. Use SharePreferences

  • Push them to SharedPreferences in Sender side
  • Get theme from SharedPreferences in other side

References

--

--

Leo N

🎓 “A person who never made a mistake never tried anything new.” — Albert Einstein