diff options
| -rw-r--r-- | api/current.txt | 5 | ||||
| -rw-r--r-- | core/java/android/os/RemoteException.java | 4 | ||||
| -rw-r--r-- | core/java/android/os/TransactionTooLargeException.java | 59 | ||||
| -rw-r--r-- | core/jni/android_util_Binder.cpp | 34 |
4 files changed, 94 insertions, 8 deletions
diff --git a/api/current.txt b/api/current.txt index 507cdeb59418..820de87f0f5a 100644 --- a/api/current.txt +++ b/api/current.txt @@ -15131,6 +15131,7 @@ package android.os { public class RemoteException extends android.util.AndroidException { ctor public RemoteException(); + ctor public RemoteException(java.lang.String); } public class ResultReceiver implements android.os.Parcelable { @@ -15225,6 +15226,10 @@ package android.os { method public abstract void released(); } + public class TransactionTooLargeException extends android.os.RemoteException { + ctor public TransactionTooLargeException(); + } + public class Vibrator { method public void cancel(); method public boolean hasVibrator(); diff --git a/core/java/android/os/RemoteException.java b/core/java/android/os/RemoteException.java index 9d76156a4974..e30d24fa05e7 100644 --- a/core/java/android/os/RemoteException.java +++ b/core/java/android/os/RemoteException.java @@ -24,4 +24,8 @@ public class RemoteException extends AndroidException { public RemoteException() { super(); } + + public RemoteException(String message) { + super(message); + } } diff --git a/core/java/android/os/TransactionTooLargeException.java b/core/java/android/os/TransactionTooLargeException.java new file mode 100644 index 000000000000..25f09e80ea77 --- /dev/null +++ b/core/java/android/os/TransactionTooLargeException.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; +import android.os.RemoteException; + +/** + * The Binder transaction failed because it was too large. + * <p> + * During a remote procedure call, the arguments and the return value of the call + * are transferred as {@link 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 {@link TransactionTooLargeException} will be thrown. + * </p><p> + * 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. + * </p><p> + * There are two possible outcomes when a remote procedure call throws + * {@link 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). It is not possible to tell which of these outcomes + * actually occurred. The client should assume that a partial failure occurred. + * </p><p> + * The key to avoiding {@link TransactionTooLargeException} is to keep all + * transactions relatively small. Try to minimize the amount of memory needed to create + * a {@link Parcel} for the arguments and the return value of the remote procedure call. + * Avoid transferring huge arrays of strings or large bitmaps. + * If possible, try to break up big requests into smaller pieces. + * </p><p> + * If you are implementing a service, it may help to impose size or complexity + * contraints on the queries that clients can perform. For example, if the result set + * could become large, then don't allow the client to request more than a few records + * at a time. Alternately, instead of returning all of the available data all at once, + * return the essential information first and make the client ask for additional information + * later as needed. + * </p> + */ +public class TransactionTooLargeException extends RemoteException { + public TransactionTooLargeException() { + super(); + } +} diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index 1718e741d8d0..2bd4fa00e612 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -38,6 +38,7 @@ #include <binder/ProcessState.h> #include <binder/IServiceManager.h> #include <utils/threads.h> +#include <utils/String8.h> #include <ScopedUtfChars.h> #include <ScopedLocalRef.h> @@ -651,7 +652,8 @@ jobject newParcelFileDescriptor(JNIEnv* env, jobject fileDesc) gParcelFileDescriptorOffsets.mClass, gParcelFileDescriptorOffsets.mConstructor, fileDesc); } -void signalExceptionForError(JNIEnv* env, jobject obj, status_t err) +static void signalExceptionForError(JNIEnv* env, jobject obj, status_t err, + bool canThrowRemoteException = false) { switch (err) { case UNKNOWN_ERROR: @@ -688,14 +690,25 @@ void signalExceptionForError(JNIEnv* env, jobject obj, status_t err) jniThrowException(env, "java/lang/RuntimeException", "Item already exists"); break; case DEAD_OBJECT: - jniThrowException(env, "android/os/DeadObjectException", NULL); + // DeadObjectException is a checked exception, only throw from certain methods. + jniThrowException(env, canThrowRemoteException + ? "android/os/DeadObjectException" + : "java/lang/RuntimeException", NULL); break; case UNKNOWN_TRANSACTION: jniThrowException(env, "java/lang/RuntimeException", "Unknown transaction code"); break; case FAILED_TRANSACTION: LOGE("!!! FAILED BINDER TRANSACTION !!!"); - //jniThrowException(env, "java/lang/OutOfMemoryError", "Binder transaction too large"); + // 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); break; case FDS_NOT_ALLOWED: jniThrowException(env, "java/lang/RuntimeException", @@ -703,6 +716,12 @@ void signalExceptionForError(JNIEnv* env, jobject obj, status_t err) break; default: LOGE("Unknown binder error code. 0x%x", err); + String8 msg; + msg.appendFormat("Unknown binder error code. 0x%x", err); + // RemoteException is a checked exception, only throw from certain methods. + jniThrowException(env, canThrowRemoteException + ? "android/os/RemoteException" : "java/lang/RuntimeException", msg.string()); + break; } } @@ -1036,8 +1055,7 @@ static bool should_time_binder_calls() { } static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj, - jint code, jobject dataObj, - jobject replyObj, jint flags) + jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException { if (dataObj == NULL) { jniThrowNullPointerException(env, NULL); @@ -1084,12 +1102,12 @@ static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj, return JNI_FALSE; } - signalExceptionForError(env, obj, err); + signalExceptionForError(env, obj, err, true /*canThrowRemoteException*/); return JNI_FALSE; } static void android_os_BinderProxy_linkToDeath(JNIEnv* env, jobject obj, - jobject recipient, jint flags) + jobject recipient, jint flags) // throws RemoteException { if (recipient == NULL) { jniThrowNullPointerException(env, NULL); @@ -1114,7 +1132,7 @@ static void android_os_BinderProxy_linkToDeath(JNIEnv* env, jobject obj, // Failure adding the death recipient, so clear its reference // now. jdr->clearReference(); - signalExceptionForError(env, obj, err); + signalExceptionForError(env, obj, err, true /*canThrowRemoteException*/); } } } |