am e7de36e6: Merge "Throw TransactionTooLargeException when Binder transaction fails. Bug: 5578022" into ics-mr1

* commit 'e7de36e605e0ccf4552c8ee1db40cb9af3227cf4':
  Throw TransactionTooLargeException when Binder transaction fails. Bug: 5578022
This commit is contained in:
Jeff Brown
2011-11-09 19:21:50 +00:00
committed by Android Git Automerger
4 changed files with 94 additions and 8 deletions

View File

@@ -15132,6 +15132,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 {
@@ -15226,6 +15227,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();

View File

@@ -24,4 +24,8 @@ public class RemoteException extends AndroidException {
public RemoteException() {
super();
}
public RemoteException(String message) {
super(message);
}
}

View File

@@ -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();
}
}

View File

@@ -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*/);
}
}
}