diff options
author | Dianne Hackborn <hackbod@google.com> | 2015-05-19 16:04:04 -0700 |
---|---|---|
committer | Dianne Hackborn <hackbod@google.com> | 2015-05-21 18:19:50 -0700 |
commit | e5c42621095a12e7d22ca5ab871dacd28c9bff41 (patch) | |
tree | 2ba8e545b5c97ede4be9532d08e0cd03cd24e0b5 | |
parent | 8b20cdb27bc5b4c433c4fc650203be9a25842bbd (diff) | |
download | frameworks_base-e5c42621095a12e7d22ca5ab871dacd28c9bff41.zip frameworks_base-e5c42621095a12e7d22ca5ab871dacd28c9bff41.tar.gz frameworks_base-e5c42621095a12e7d22ca5ab871dacd28c9bff41.tar.bz2 |
Improve reporting to apps of transaction too large failures.
If the app tried to do various things with too much data --
starting an activity, starting a service, sending a broadcast --
this would fairly silently fail with little indication of what
was going on. Fix this in two ways:
- Now when the native code generates a TransactionTooLargeException,
it may include an additional message in it telling you how much
data was in the parcel being sent, to help you understand why
this happening.
- In all the framework code paths where we call to the system and
may fail, convert these failures into a a runtime exception and
rethrow them back to the app so that it will clearly get the
above message.
Change-Id: I745159b97d3edb6fca86aa09cbc40c1f15a7d128
-rw-r--r-- | api/current.txt | 1 | ||||
-rw-r--r-- | api/system-current.txt | 1 | ||||
-rw-r--r-- | core/java/android/app/ContextImpl.java | 27 | ||||
-rw-r--r-- | core/java/android/app/Instrumentation.java | 6 | ||||
-rw-r--r-- | core/java/android/os/TransactionTooLargeException.java | 4 | ||||
-rw-r--r-- | core/jni/android_util_Binder.cpp | 15 | ||||
-rw-r--r-- | core/jni/android_util_Binder.h | 2 | ||||
-rw-r--r-- | tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java | 9 |
8 files changed, 52 insertions, 13 deletions
diff --git a/api/current.txt b/api/current.txt index d8cbb9a..00ae23f 100644 --- a/api/current.txt +++ b/api/current.txt @@ -23576,6 +23576,7 @@ package android.os { public class TransactionTooLargeException extends android.os.RemoteException { ctor public TransactionTooLargeException(); + ctor public TransactionTooLargeException(java.lang.String); } public final class UserHandle implements android.os.Parcelable { diff --git a/api/system-current.txt b/api/system-current.txt index 1610869..b43b665 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -25498,6 +25498,7 @@ package android.os { public class TransactionTooLargeException extends android.os.RemoteException { ctor public TransactionTooLargeException(); + ctor public TransactionTooLargeException(java.lang.String); } public final class UserHandle implements android.os.Parcelable { diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index cb20cb8..3b1ccd2 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -689,7 +689,8 @@ class ContextImpl extends Context { intent.resolveTypeIfNeeded(getContentResolver()), null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, options, user.getIdentifier()); - } catch (RemoteException re) { + } catch (RemoteException e) { + throw new RuntimeException("Failure from system", e); } } @@ -754,6 +755,7 @@ class ContextImpl extends Context { } Instrumentation.checkStartActivityResult(result, null); } catch (RemoteException e) { + throw new RuntimeException("Failure from system", e); } } @@ -768,6 +770,7 @@ class ContextImpl extends Context { Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, false, getUserId()); } catch (RemoteException e) { + throw new RuntimeException("Failure from system", e); } } @@ -782,6 +785,7 @@ class ContextImpl extends Context { Activity.RESULT_OK, null, null, receiverPermission, AppOpsManager.OP_NONE, false, false, getUserId()); } catch (RemoteException e) { + throw new RuntimeException("Failure from system", e); } } @@ -796,6 +800,7 @@ class ContextImpl extends Context { Activity.RESULT_OK, null, null, receiverPermission, appOp, false, false, getUserId()); } catch (RemoteException e) { + throw new RuntimeException("Failure from system", e); } } @@ -811,6 +816,7 @@ class ContextImpl extends Context { Activity.RESULT_OK, null, null, receiverPermission, AppOpsManager.OP_NONE, true, false, getUserId()); } catch (RemoteException e) { + throw new RuntimeException("Failure from system", e); } } @@ -854,6 +860,7 @@ class ContextImpl extends Context { initialCode, initialData, initialExtras, receiverPermission, appOp, true, false, getUserId()); } catch (RemoteException e) { + throw new RuntimeException("Failure from system", e); } } @@ -866,6 +873,7 @@ class ContextImpl extends Context { intent, resolvedType, null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, false, user.getIdentifier()); } catch (RemoteException e) { + throw new RuntimeException("Failure from system", e); } } @@ -886,6 +894,7 @@ class ContextImpl extends Context { Activity.RESULT_OK, null, null, receiverPermission, appOp, false, false, user.getIdentifier()); } catch (RemoteException e) { + throw new RuntimeException("Failure from system", e); } } @@ -927,6 +936,7 @@ class ContextImpl extends Context { initialCode, initialData, initialExtras, receiverPermission, appOp, true, false, user.getIdentifier()); } catch (RemoteException e) { + throw new RuntimeException("Failure from system", e); } } @@ -942,6 +952,7 @@ class ContextImpl extends Context { Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, true, getUserId()); } catch (RemoteException e) { + throw new RuntimeException("Failure from system", e); } } @@ -977,6 +988,7 @@ class ContextImpl extends Context { initialCode, initialData, initialExtras, null, AppOpsManager.OP_NONE, true, true, getUserId()); } catch (RemoteException e) { + throw new RuntimeException("Failure from system", e); } } @@ -993,6 +1005,7 @@ class ContextImpl extends Context { ActivityManagerNative.getDefault().unbroadcastIntent( mMainThread.getApplicationThread(), intent, getUserId()); } catch (RemoteException e) { + throw new RuntimeException("Failure from system", e); } } @@ -1006,6 +1019,7 @@ class ContextImpl extends Context { mMainThread.getApplicationThread(), intent, resolvedType, null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, true, user.getIdentifier()); } catch (RemoteException e) { + throw new RuntimeException("Failure from system", e); } } @@ -1040,6 +1054,7 @@ class ContextImpl extends Context { initialCode, initialData, initialExtras, null, AppOpsManager.OP_NONE, true, true, user.getIdentifier()); } catch (RemoteException e) { + throw new RuntimeException("Failure from system", e); } } @@ -1056,6 +1071,7 @@ class ContextImpl extends Context { ActivityManagerNative.getDefault().unbroadcastIntent( mMainThread.getApplicationThread(), intent, user.getIdentifier()); } catch (RemoteException e) { + throw new RuntimeException("Failure from system", e); } } @@ -1171,7 +1187,7 @@ class ContextImpl extends Context { } return cn; } catch (RemoteException e) { - return null; + throw new RuntimeException("Failure from system", e); } } @@ -1193,7 +1209,7 @@ class ContextImpl extends Context { } return res != 0; } catch (RemoteException e) { - return false; + throw new RuntimeException("Failure from system", e); } } @@ -1242,7 +1258,7 @@ class ContextImpl extends Context { } return res != 0; } catch (RemoteException e) { - return false; + throw new RuntimeException("Failure from system", e); } } @@ -1274,9 +1290,8 @@ class ContextImpl extends Context { className, profileFile, 0, arguments, null, null, getUserId(), null /* ABI override */); } catch (RemoteException e) { - // System has crashed, nothing we can do. + throw new RuntimeException("Failure from system", e); } - return false; } @Override diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java index b77dec5..0cc57ba 100644 --- a/core/java/android/app/Instrumentation.java +++ b/core/java/android/app/Instrumentation.java @@ -1506,6 +1506,7 @@ public class Instrumentation { requestCode, 0, null, options); checkStartActivityResult(result, intent); } catch (RemoteException e) { + throw new RuntimeException("Failure from system", e); } return null; } @@ -1563,6 +1564,7 @@ public class Instrumentation { token, options, userId); checkStartActivityResult(result, intents[0]); } catch (RemoteException e) { + throw new RuntimeException("Failure from system", e); } } @@ -1622,6 +1624,7 @@ public class Instrumentation { token, target, requestCode, 0, null, options); checkStartActivityResult(result, intent); } catch (RemoteException e) { + throw new RuntimeException("Failure from system", e); } return null; } @@ -1682,6 +1685,7 @@ public class Instrumentation { requestCode, 0, null, options, user.getIdentifier()); checkStartActivityResult(result, intent); } catch (RemoteException e) { + throw new RuntimeException("Failure from system", e); } return null; } @@ -1719,6 +1723,7 @@ public class Instrumentation { requestCode, 0, null, options, userId); checkStartActivityResult(result, intent); } catch (RemoteException e) { + throw new RuntimeException("Failure from system", e); } return null; } @@ -1753,6 +1758,7 @@ public class Instrumentation { intent, intent.resolveTypeIfNeeded(who.getContentResolver()), options); checkStartActivityResult(result, intent); } catch (RemoteException e) { + throw new RuntimeException("Failure from system", e); } return; } diff --git a/core/java/android/os/TransactionTooLargeException.java b/core/java/android/os/TransactionTooLargeException.java index 25f09e8..10abf26 100644 --- a/core/java/android/os/TransactionTooLargeException.java +++ b/core/java/android/os/TransactionTooLargeException.java @@ -56,4 +56,8 @@ public class TransactionTooLargeException extends RemoteException { public TransactionTooLargeException() { super(); } + + public TransactionTooLargeException(String msg) { + super(msg); + } } diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index 634c9f7..70a7805 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -635,7 +635,7 @@ void set_dalvik_blockguard_policy(JNIEnv* env, jint strict_policy) } void signalExceptionForError(JNIEnv* env, jobject obj, status_t err, - bool canThrowRemoteException) + bool canThrowRemoteException, int parcelSize) { switch (err) { case UNKNOWN_ERROR: @@ -680,8 +680,10 @@ void signalExceptionForError(JNIEnv* env, jobject obj, status_t err, case UNKNOWN_TRANSACTION: jniThrowException(env, "java/lang/RuntimeException", "Unknown transaction code"); break; - case FAILED_TRANSACTION: - ALOGE("!!! FAILED BINDER TRANSACTION !!!"); + case FAILED_TRANSACTION: { + ALOGE("!!! FAILED BINDER TRANSACTION !!! (parcel size = %d)", parcelSize); + char msg[128]; + snprintf(msg, sizeof(msg)-1, "data parcel size %d bytes", parcelSize); // 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 @@ -690,8 +692,9 @@ void signalExceptionForError(JNIEnv* env, jobject obj, status_t err, // to enable us to distinguish these cases in the future. jniThrowException(env, canThrowRemoteException ? "android/os/TransactionTooLargeException" - : "java/lang/RuntimeException", NULL); - break; + : "java/lang/RuntimeException", + parcelSize > 0 ? msg : NULL); + } break; case FDS_NOT_ALLOWED: jniThrowException(env, "java/lang/RuntimeException", "Not allowed to write file descriptors here"); @@ -1121,7 +1124,7 @@ static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj, return JNI_FALSE; } - signalExceptionForError(env, obj, err, true /*canThrowRemoteException*/); + signalExceptionForError(env, obj, err, true /*canThrowRemoteException*/, data->dataSize()); return JNI_FALSE; } diff --git a/core/jni/android_util_Binder.h b/core/jni/android_util_Binder.h index ca320ef..c109d6c 100644 --- a/core/jni/android_util_Binder.h +++ b/core/jni/android_util_Binder.h @@ -33,7 +33,7 @@ extern jobject newParcelFileDescriptor(JNIEnv* env, jobject fileDesc); extern void set_dalvik_blockguard_policy(JNIEnv* env, jint strict_policy); extern void signalExceptionForError(JNIEnv* env, jobject obj, status_t err, - bool canThrowRemoteException = false); + bool canThrowRemoteException = false, int parcelSize = 0); } diff --git a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java index fc66d6d..ddcfd9e 100644 --- a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java +++ b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java @@ -427,6 +427,15 @@ public class ActivityTestMain extends Activity { return true; } }); + menu.add("Transaction fail").setOnMenuItemClickListener( + new MenuItem.OnMenuItemClickListener() { + @Override public boolean onMenuItemClick(MenuItem item) { + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.putExtra("gulp", new int[1024*1024]); + startActivity(intent); + return true; + } + }); return true; } |