Android remote method data limit - android

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.

Related

Why DeadObjectException during AIDL call using byte[] but not Bitmap?

Let's say there are two processes. I am interested in making an AIDL call (e.g. byte[] getBytes()) from an Activity (Process A) to a Service (Process B) which returns a byte[] of data.
However when this byte[] of data exceeds 1MB, it triggers the following expected exception. This also happens if the byte[] is wrapped inside of a custom Parcelable class.
W Error = android.os.DeadObjectException: Transaction failed on small parcel; remote process probably died
W at android.os.BinderProxy.transactNative(Native Method)
W at android.os.BinderProxy.transact(BinderProxy.java:571)
This appears to be caused by the data limits documented here: https://developer.android.com/guide/components/activities/parcelables-and-bundles
However, if the AIDL API returns a Bitmap (e.g. Bitmap getBitmap() ) containing data for an image that exceeds 1MB, this exception does not get triggered. Why does it work? In general, if I'd like to send data over 1MB, what would be the preferred method? In this test case, it's using an image file for the Bitmap but what if it is an audio file, video file or something else?
It depends. An implementation of Bitmap may not contain all of the image data in an array- it may contain information needed to get that data. For example, it may contain the filename of an image, and accessing the data would try to reopen the file. (whether that would work would depend on access rights of both apps). Or provide the URI of a content provider it can query for the data. Could that technique work with other data? Yes, if there's a reasonable way to do that. But there needs to be a way for the receiving app to reacquire the full data set.
However the 1MB limit to the size of a Bundle (the underlying class used to send data via AIDL) is hardcoded at the OS level. You can't get around it and put more in the bundle. You can only do a misdirection like this.

android Intents inline-data size limit

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

Find binder object in parcel

How can i find binder object in a android parcel? i want to marshall a parcel which has got a bitmap but i got Runtime exception says that the parcel has got binder object.
Sadly, you can't. A Parcel is unfortunately sometimes more than just a stream of bytes. Occasionally it contains an intelligent object, called a Binder. These objects can be passed around using IPC and have methods called by different processes in different parts of the Android system.
That's what's happening in this case. When you called Bitmap.writeToParcel() it's putting some intelligent object in there, which needs to be queried by other parts of the OS. That means that this Parcel simply can't be reduced to a stream of bytes.
(Specifically I think what's happening is this - but I could be wrong. I believe that this code:
http://androidxref.com/4.1.1/xref/frameworks/native/libs/binder/Parcel.cpp#736
is writing the bitmap data to an area of shared memory, and putting a reference to that shared memory area into the parcel. This means that the data doesn't need to be copied so often, which is great when you're passing the Parcel to another process using IPC, but not so good if you're just using it to serialize data.)
Using Parcel.marshall sometimes suggests bad design... as the comment says,
The data you retrieve here must not be placed in any kind of persistent storage (on local disk, across a network, etc). For that, you should use standard serialization or another kind of general serialization mechanism. The Parcel marshalled representation is highly optimized for local IPC, and as such does not attempt to maintain compatibility with data created in different versions of the platform.
If you are using it for local IPC, then you shouldn't need to call Parcel.marshall - because normally it would be part of an AIDL interface where these things are handled automatically.
Sorry there's no immediate solution! If you're using it for IPC, then use AIDL. If you're using it for something else, then don't use Parcel.marshall - instead you'll have to go to more effort to write the bitmap bytes to your own data format.

Is there any limit of bundle in Android?

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.

Which is less performance intensive - passing a bundle via an Intent or using a Content Provider

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.

Categories

Resources