I want to know whether android bundle's data size has upper limit. I try to post data by bundle which size >80k,and throw android fatal exception.The data is Serializable.
It depends on the purpose of the bundle. The bundle itself is only limited by the amount of memory.
The two main uses for bundles are to pass information between components using intents and to save the state of activities.
1. Intents / Binders
When used to pass information between Android components the bundle is serialized into a binder transaction. The total size for all binder transactions in a process is 1MB. If you exceed this limit you will receive this fatal error "!!! FAILED BINDER TRANSACTION !!!"
It's recommend that you keep the data in these bundles as small as possible because it's a shared buffer, anything more than a few kilobytes should be written to disk.
Reference: https://android.googlesource.com/platform/frameworks/base/+/jb-release/core/jni/android_util_Binder.cpp
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.
Reference: http://developer.android.com/reference/android/os/TransactionTooLargeException.html
The Binder transaction buffer has a limited fixed size, currently 1Mb, which is shared by all transactions in progress for the process. Consequently this exception can be thrown when there are many transactions in progress even when most of the individual transactions are of moderate size.
2. Saved Instance State ( Activity onSaveInstanceState, onPause etc. )
I found no limit in the size I could store in the bundle used to preserve Activity state. I did some tests and could successfully store about 175mb before I received an out of memory exception trying to allocate the data I was attempting to save.
Update: This research was performed in 2014, newer versions of Android may crash with bundles over 500kb
I think the limit is 500kb.
You can save the passed object in a file and send the path of the file in the bundle instead.
You can check similar question asked by me at SO
The Binder transaction buffer has a limited fixed size, currently 1MB, which is shared by all transactions in progress for the process. Since this limit is at the process level rather than at the per activity level, these transactions include all binder transactions in the app such as onSaveInstanceState, startActivity and any interaction with the system. When the size limit is exceeded, a TransactionTooLargeException is thrown.
For the specific case of savedInstanceState, the amount of data should be kept small because the system process needs to hold on to the provided data for as long as the user can ever navigate back to that activity (even if the activity's process is killed). We recommend that you keep saved state to less than 50k of data.
Parcelable and Bundles
Yes it has, and now in android Nougat it will crash if you exceeded the limit roughly(500Kb).
android nougat issue
I think that the maximum bundle size is 1024 KiloBytes. In order to transfer large objects among activities, you should try other ways (memory cache, local storage, etc).
According to the Google Android API, the date should be less than 50K.
Yes it has 1MB limit.
You can use Singleton class to pass data.
Related
I am sending data via broadcasts like this:
Intent outIntent = new Intent(Const.ACTION_FEED);
outIntent.putExtra(Const.EXTRA_FEED, data);
sendBroadcast(outIntent);
The issue is that data can get quite large, resulting in a TransactionTooLargeException. The documentation says:
The Binder transaction buffer has a limited fixed size, currently 1Mb, which is shared by all transactions in progress for the process. Consequently this exception can be thrown when there are many transactions in progress even when most of the individual transactions are of moderate size.
Bottom line: it seems to be impossible to tell in advance what size is acceptable for data.
Furthermore:
The key to avoiding TransactionTooLargeException is to keep all transactions relatively small. [...] If possible, try to break up big requests into smaller pieces.
The nature of the data I am sending is such that I could easily break it down into smaller pieces and send them individually, once I have established that the whole thing is too big to send at once.
The logical step would be to wrap the whole code in a try/catch block, and upon receiving a TransactionTooLarge exception, chop up the data into smaller chunks and retry.
Alas, according to the logcat, the exception is not thrown at the caller’s end but in a system process. The system then goes on to crash the receiver of the broadcast, at which point any recovery is out of the sender’s control.
How can I tell how much data is OK to send as a broadcast extra, and prevent crashing the receiver of the data?
While I am somewhat familiar with the process Binders use to communicate across processes, I was wondering if the fact that they have to interact with the Binder Driver on kernel significantly increased the memory overhead of creating the object.
Furthermore, does creating a significant number of Binders limit the transaction speed of existing Binders even if the number of transactions doesn't increase?
You'd have to dig into the libbinder code as well as the kernel driver code to really do an analysis of memory consumption. However, the overhead is likely not very much as internally the binder driver has its driver object then links to the actual binders owned by the calling process. It also limits the number of threads which can be used by calling processes to handle simultaneous transactions.
As far as performance goes, the main limiting factor is going to be the size of the transaction data through a given binder. Each binder gets a fixed size buffer (1MB) to handle all transactions for that binder. So if there are multiple transactions going on simultaneously for a specific binder, the total data used by all of them is what counts against this limit. This can be very tricky to troubleshoot or handle gracefully as the exception which occurs (Java level) does not indicate if it was the send part of the transaction or the receive part. The rule of thumb is that data moving across a binder needs to be small, like message passing. It's not well suited for something like streaming data. Android uses the ashmem driver support to better handle this as well as the ability to share file descriptors across binders.
The binders themselves are tracked in a btree, so lookup should be extremely fast. It would be interesting to have some stats on this for a given process as well as if the total number of binders in the system gets to a high level, but I'm not aware of any such data.
I have found that the android stock camera app, when passing an image back to a caller via a parcelable on an intent reduces the size to ~50k.
Search for the next text in the below source code link: Limit to 50k pixels so we can return it in the intent
Source Code Link: Android Stock Camera Source Code
My question is, why this limit, and what are the real size limits of data I can pass via an intent? I could find forums talking about this, but no real documentation from Google on the limits.
This is related to the binder transaction buffer:
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.
The Binder transaction buffer has a limited fixed size, currently 1Mb, which is shared by all transactions in progress for the process. Consequently this exception can be thrown when there are many transactions in progress even when most of the individual transactions are of moderate size. 1
If you exceed the Binder transaction buffer limit, you'll get a TransactionTooLargeException.
The limit is supposed to be 1MB but it varies by device from little less than 512KB up to almost a full 1MB.
Android Documentation
for my application I need to pass data between my activity and the the service both of which are in different processes. I know that Google recommends to keep the data passed while sending intent to a minimum (not full size bitmaps). Does a similar policy apply when you are communicating with the service over AIDL and want to pass the data via remote method calls?
http://developer.android.com/reference/android/os/TransactionTooLargeException.html
" 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.
The Binder transaction buffer has a limited fixed size, currently 1Mb, which is shared by all transactions in progress for the process. "
So it seems, you should never send any arguments which are more than 1MB in size. Of course you could fail with lesser sized arguments too as explained on android site above.
I'm not sure about AIDL, but typically you DO want to keep Intent extras to a minimum. A better solution may be to implement your own ContentProvider and use that to provide data to your other process. This will allow for managed data transfer, and gives you all the extra protections that the ContentProvider API provides.
I would like to pass a considerable sized amount of data (~1500 bytes) between two applications in Android where performance and resource allocation is a priority. The data is basically key-value pairs. The rate at which it needs to be passed from one application to another can vary from a trickle to ~50 packets within a second. I figure I can either:
Wrap all the data inside a bundle, and pass the bundle via an Intent from one application to another. I worry about the performance implications of allocating and de-allocating all that memory to store the bundles.
Write all the data to a SQLite database and provide it to the other application via a content provider. Here I worry about the performance implications of writing all that data to disk, and then having to read it back from disk when it is requested.
So, which is the lesser of two evils?
Consider using a service connection. You pay some overhead in setting up the initial connection, but after that, you can use an RPC-like interface to make method calls (passing Parcelable structures in either direction) with very little overhead (well under a millisecond). See this page for details.