1 /*
2  * Copyright (C) 2014 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 
17 package android.util;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.os.ParcelableException;
22 
23 import com.android.internal.util.Preconditions;
24 
25 import java.io.IOException;
26 
27 /**
28  * Utility methods for proxying richer exceptions across Binder calls.
29  *
30  * @hide
31  */
32 public class ExceptionUtils {
wrap(IOException e)33     public static RuntimeException wrap(IOException e) {
34         throw new ParcelableException(e);
35     }
36 
maybeUnwrapIOException(RuntimeException e)37     public static void maybeUnwrapIOException(RuntimeException e) throws IOException {
38         if (e instanceof ParcelableException) {
39             ((ParcelableException) e).maybeRethrow(IOException.class);
40         }
41     }
42 
getCompleteMessage(String msg, Throwable t)43     public static String getCompleteMessage(String msg, Throwable t) {
44         final StringBuilder builder = new StringBuilder();
45         if (msg != null) {
46             builder.append(msg).append(": ");
47         }
48         builder.append(t.getMessage());
49         while ((t = t.getCause()) != null) {
50             builder.append(": ").append(t.getMessage());
51         }
52         return builder.toString();
53     }
54 
getCompleteMessage(Throwable t)55     public static String getCompleteMessage(Throwable t) {
56         return getCompleteMessage(null, t);
57     }
58 
propagateIfInstanceOf( @ullable Throwable t, Class<E> c)59     public static <E extends Throwable> void propagateIfInstanceOf(
60             @Nullable Throwable t, Class<E> c) throws E {
61         if (t != null && c.isInstance(t)) {
62             throw c.cast(t);
63         }
64     }
65 
66     /**
67      * @param <E> a checked exception that is ok to throw without wrapping
68      */
propagate(@onNull Throwable t, Class<E> c)69     public static <E extends Exception> RuntimeException propagate(@NonNull Throwable t, Class<E> c)
70             throws E {
71         propagateIfInstanceOf(t, c);
72         return propagate(t);
73     }
74 
propagate(@onNull Throwable t)75     public static RuntimeException propagate(@NonNull Throwable t) {
76         Preconditions.checkNotNull(t);
77         propagateIfInstanceOf(t, Error.class);
78         propagateIfInstanceOf(t, RuntimeException.class);
79         throw new RuntimeException(t);
80     }
81 
82     /**
83      * Gets the root {@link Throwable#getCause() cause} of {@code t}
84      */
getRootCause(@onNull Throwable t)85     public static @NonNull Throwable getRootCause(@NonNull Throwable t) {
86         while (t.getCause() != null) t = t.getCause();
87         return t;
88     }
89 
90     /**
91      * Appends {@code cause} at the end of the causal chain of {@code t}
92      *
93      * @return {@code t} for convenience
94      */
appendCause(@onNull Throwable t, @Nullable Throwable cause)95     public static @NonNull Throwable appendCause(@NonNull Throwable t, @Nullable Throwable cause) {
96         if (cause != null) {
97             getRootCause(t).initCause(cause);
98         }
99         return t;
100     }
101 }