1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.os;
18
19import java.io.IOException;
20
21/**
22 * Wrapper class that offers to transport typical {@link Throwable} across a
23 * {@link Binder} call. This class is typically used to transport exceptions
24 * that cannot be modified to add {@link Parcelable} behavior, such as
25 * {@link IOException}.
26 * <ul>
27 * <li>The wrapped throwable must be defined as system class (that is, it must
28 * be in the same {@link ClassLoader} as {@link Parcelable}).
29 * <li>The wrapped throwable must support the
30 * {@link Throwable#Throwable(String)} constructor.
31 * <li>The receiver side must catch any thrown {@link ParcelableException} and
32 * call {@link #maybeRethrow(Class)} for all expected exception types.
33 * </ul>
34 *
35 * @hide
36 */
37public final class ParcelableException extends RuntimeException implements Parcelable {
38    public ParcelableException(Throwable t) {
39        super(t);
40    }
41
42    @SuppressWarnings("unchecked")
43    public <T extends Throwable> void maybeRethrow(Class<T> clazz) throws T {
44        if (clazz.isAssignableFrom(getCause().getClass())) {
45            throw (T) getCause();
46        }
47    }
48
49    /** {@hide} */
50    public static Throwable readFromParcel(Parcel in) {
51        final String name = in.readString();
52        final String msg = in.readString();
53        try {
54            final Class<?> clazz = Class.forName(name, true, Parcelable.class.getClassLoader());
55            return (Throwable) clazz.getConstructor(String.class).newInstance(msg);
56        } catch (ReflectiveOperationException e) {
57            throw new RuntimeException(name + ": " + msg);
58        }
59    }
60
61    /** {@hide} */
62    public static void writeToParcel(Parcel out, Throwable t) {
63        out.writeString(t.getClass().getName());
64        out.writeString(t.getMessage());
65    }
66
67    @Override
68    public int describeContents() {
69        return 0;
70    }
71
72    @Override
73    public void writeToParcel(Parcel dest, int flags) {
74        writeToParcel(dest, getCause());
75    }
76
77    public static final Creator<ParcelableException> CREATOR = new Creator<ParcelableException>() {
78        @Override
79        public ParcelableException createFromParcel(Parcel source) {
80            return new ParcelableException(readFromParcel(source));
81        }
82
83        @Override
84        public ParcelableException[] newArray(int size) {
85            return new ParcelableException[size];
86        }
87    };
88}
89