diff options
| author | Jeff Sharkey <jsharkey@android.com> | 2017-01-20 22:50:49 +0000 |
|---|---|---|
| committer | android-build-merger <android-build-merger@google.com> | 2017-01-20 22:50:49 +0000 |
| commit | c3fbf32011d7c6a914fda1cc1b7a33b4ffd132f4 (patch) | |
| tree | aeca76e291d2935e2bcbfdbab179492e8737898e /core/java/android | |
| parent | 74247b4ee884678903f994c2a935898858b79501 (diff) | |
| parent | a2ef6b5741e9dfc02cac1376b3b743ac2cdbefd9 (diff) | |
Merge "Add Binder support for Parcelable exceptions."
am: a2ef6b5741
Change-Id: Ide766c0220e86b7661af83551354b3a498297ed8
Diffstat (limited to 'core/java/android')
| -rw-r--r-- | core/java/android/os/Parcel.java | 33 | ||||
| -rw-r--r-- | core/java/android/os/ParcelableException.java | 88 | ||||
| -rw-r--r-- | core/java/android/util/ExceptionUtils.java | 14 |
3 files changed, 123 insertions, 12 deletions
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index f6e6ad6067bb..b5ab908346d9 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -27,6 +27,8 @@ import android.util.SizeF; import android.util.SparseArray; import android.util.SparseBooleanArray; +import libcore.util.SneakyThrow; + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileDescriptor; @@ -249,6 +251,7 @@ public final class Parcel { private static final int EX_NETWORK_MAIN_THREAD = -6; private static final int EX_UNSUPPORTED_OPERATION = -7; private static final int EX_SERVICE_SPECIFIC = -8; + private static final int EX_PARCELABLE = -9; private static final int EX_HAS_REPLY_HEADER = -128; // special; see below // EX_TRANSACTION_FAILED is used exclusively in native code. // see libbinder's binder/Status.h @@ -1555,7 +1558,12 @@ public final class Parcel { */ public final void writeException(Exception e) { int code = 0; - if (e instanceof SecurityException) { + if (e instanceof Parcelable + && (e.getClass().getClassLoader() == Parcelable.class.getClassLoader())) { + // We only send Parcelable exceptions that are in the + // BootClassLoader to ensure that the receiver can unpack them + code = EX_PARCELABLE; + } else if (e instanceof SecurityException) { code = EX_SECURITY; } else if (e instanceof BadParcelableException) { code = EX_BAD_PARCELABLE; @@ -1581,8 +1589,20 @@ public final class Parcel { throw new RuntimeException(e); } writeString(e.getMessage()); - if (e instanceof ServiceSpecificException) { - writeInt(((ServiceSpecificException)e).errorCode); + switch (code) { + case EX_SERVICE_SPECIFIC: + writeInt(((ServiceSpecificException) e).errorCode); + break; + case EX_PARCELABLE: + // Write parceled exception prefixed by length + final int sizePosition = dataPosition(); + writeInt(0); + writeParcelable((Parcelable) e, Parcelable.PARCELABLE_WRITE_RETURN_VALUE); + final int payloadPosition = dataPosition(); + setDataPosition(sizePosition); + writeInt(payloadPosition - sizePosition); + setDataPosition(payloadPosition); + break; } } @@ -1680,6 +1700,13 @@ public final class Parcel { */ public final void readException(int code, String msg) { switch (code) { + case EX_PARCELABLE: + if (readInt() > 0) { + SneakyThrow.sneakyThrow( + (Exception) readParcelable(Parcelable.class.getClassLoader())); + } else { + throw new RuntimeException(msg + " [missing Parcelable]"); + } case EX_SECURITY: throw new SecurityException(msg); case EX_BAD_PARCELABLE: diff --git a/core/java/android/os/ParcelableException.java b/core/java/android/os/ParcelableException.java new file mode 100644 index 000000000000..d84d62997d93 --- /dev/null +++ b/core/java/android/os/ParcelableException.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2017 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 java.io.IOException; + +/** + * Wrapper class that offers to transport typical {@link Throwable} across a + * {@link Binder} call. This class is typically used to transport exceptions + * that cannot be modified to add {@link Parcelable} behavior, such as + * {@link IOException}. + * <ul> + * <li>The wrapped throwable must be defined as system class (that is, it must + * be in the same {@link ClassLoader} as {@link Parcelable}). + * <li>The wrapped throwable must support the + * {@link Throwable#Throwable(String)} constructor. + * <li>The receiver side must catch any thrown {@link ParcelableException} and + * call {@link #maybeRethrow(Class)} for all expected exception types. + * </ul> + * + * @hide + */ +public final class ParcelableException extends RuntimeException implements Parcelable { + public ParcelableException(Throwable t) { + super(t); + } + + @SuppressWarnings("unchecked") + public <T extends Throwable> void maybeRethrow(Class<T> clazz) throws T { + if (clazz.isAssignableFrom(getCause().getClass())) { + throw (T) getCause(); + } + } + + /** {@hide} */ + public static Throwable readFromParcel(Parcel in) { + final String name = in.readString(); + final String msg = in.readString(); + try { + final Class<?> clazz = Class.forName(name, true, Parcelable.class.getClassLoader()); + return (Throwable) clazz.getConstructor(String.class).newInstance(msg); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(name + ": " + msg); + } + } + + /** {@hide} */ + public static void writeToParcel(Parcel out, Throwable t) { + out.writeString(t.getClass().getName()); + out.writeString(t.getMessage()); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + writeToParcel(dest, getCause()); + } + + public static final Creator<ParcelableException> CREATOR = new Creator<ParcelableException>() { + @Override + public ParcelableException createFromParcel(Parcel source) { + return new ParcelableException(readFromParcel(source)); + } + + @Override + public ParcelableException[] newArray(int size) { + return new ParcelableException[size]; + } + }; +} diff --git a/core/java/android/util/ExceptionUtils.java b/core/java/android/util/ExceptionUtils.java index f5d515d5e5d5..da0b609dbd9b 100644 --- a/core/java/android/util/ExceptionUtils.java +++ b/core/java/android/util/ExceptionUtils.java @@ -16,6 +16,8 @@ package android.util; +import android.os.ParcelableException; + import java.io.IOException; /** @@ -24,19 +26,13 @@ import java.io.IOException; * @hide */ public class ExceptionUtils { - // TODO: longer term these should be replaced with first-class - // Parcel.read/writeException() and AIDL support, but for now do this using - // a nasty hack. - - private static final String PREFIX_IO = "\u2603"; - public static RuntimeException wrap(IOException e) { - throw new IllegalStateException(PREFIX_IO + e.getMessage()); + throw new ParcelableException(e); } public static void maybeUnwrapIOException(RuntimeException e) throws IOException { - if ((e instanceof IllegalStateException) && e.getMessage().startsWith(PREFIX_IO)) { - throw new IOException(e.getMessage().substring(PREFIX_IO.length())); + if (e instanceof ParcelableException) { + ((ParcelableException) e).maybeRethrow(IOException.class); } } |
