Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e7de36e6 authored by Jeff Brown's avatar Jeff Brown Committed by Android (Google) Code Review
Browse files

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

parents 34dd937b 0bde66a8
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -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();
+4 −0
Original line number Diff line number Diff line
@@ -24,4 +24,8 @@ public class RemoteException extends AndroidException {
    public RemoteException() {
        super();
    }

    public RemoteException(String message) {
        super(message);
    }
}
+59 −0
Original line number Diff line number Diff line
/*
 * 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();
    }
}
+26 −8
Original line number Diff line number Diff line
@@ -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*/);
        }
    }
}