1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 package java.lang;
19 
20 import java.io.IOException;
21 import java.io.ObjectInputStream;
22 import java.io.ObjectOutputStream;
23 import java.io.PrintStream;
24 import java.io.PrintWriter;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.List;
28 import libcore.util.EmptyArray;
29 
30 /**
31  * The superclass of all classes which can be thrown by the VM. The
32  * two direct subclasses are recoverable exceptions ({@code Exception}) and
33  * unrecoverable errors ({@code Error}). This class provides common methods for
34  * accessing a string message which provides extra information about the
35  * circumstances in which the {@code Throwable} was created (basically an error
36  * message in most cases), and for saving a stack trace (that is, a record of
37  * the call stack at a particular point in time) which can be printed later.
38  *
39  * <p>A {@code Throwable} can also include a cause, which is a nested {@code
40  * Throwable} that represents the original problem that led to this {@code
41  * Throwable}. It is often used for wrapping various types of errors into a
42  * common {@code Throwable} without losing the detailed original error
43  * information. When printing the stack trace, the trace of the cause is
44  * included.
45  *
46  * @see Error
47  * @see Exception
48  * @see RuntimeException
49  */
50 public class Throwable implements java.io.Serializable {
51     private static final long serialVersionUID = -3042686055658047285L;
52 
53     /**
54      * The message provided when the exception was created.
55      */
56     private String detailMessage;
57 
58     /**
59      * The cause of this Throwable. Null when there is no cause.
60      */
61     private Throwable cause = this;
62 
63     /**
64      * Throwables suppressed by this throwable. Null when suppressed exceptions
65      * are disabled.
66      */
67     private List<Throwable> suppressedExceptions = Collections.emptyList();
68 
69     /**
70      * An intermediate representation of the stack trace.  This field may
71      * be accessed by the VM; do not rename.
72      */
73     private transient volatile Object stackState;
74 
75     /**
76      * A fully-expanded representation of the stack trace.
77      */
78     private StackTraceElement[] stackTrace;
79 
80     /**
81      * Constructs a new {@code Throwable} that includes the current stack trace.
82      */
Throwable()83     public Throwable() {
84         this.stackTrace = EmptyArray.STACK_TRACE_ELEMENT;
85         fillInStackTrace();
86     }
87 
88     /**
89      * Constructs a new {@code Throwable} with the current stack trace and the
90      * given detail message.
91      */
Throwable(String detailMessage)92     public Throwable(String detailMessage) {
93         this.detailMessage = detailMessage;
94         this.stackTrace = EmptyArray.STACK_TRACE_ELEMENT;
95         fillInStackTrace();
96     }
97 
98     /**
99      * Constructs a new {@code Throwable} with the current stack trace, the
100      * given detail message and cause.
101      */
Throwable(String detailMessage, Throwable cause)102     public Throwable(String detailMessage, Throwable cause) {
103         this.detailMessage = detailMessage;
104         this.cause = cause;
105         this.stackTrace = EmptyArray.STACK_TRACE_ELEMENT;
106         fillInStackTrace();
107     }
108 
109     /**
110      * Constructs a new {@code Throwable} with the current stack trace and the
111      * given cause.
112      */
Throwable(Throwable cause)113     public Throwable(Throwable cause) {
114         this.detailMessage = cause == null ? null : cause.toString();
115         this.cause = cause;
116         this.stackTrace = EmptyArray.STACK_TRACE_ELEMENT;
117         fillInStackTrace();
118     }
119 
120     /**
121      * Constructs a new {@code Throwable} with the current stack trace, the
122      * specified detail message and the specified cause.
123      *
124      * @param enableSuppression if false, {@link #addSuppressed(Throwable)} will be a no-op.
125      * @param writableStackTrace if false, {@link #fillInStackTrace} will not be called,
126      * this object's {@code stackTrace} will be null,
127      * calls to {@link #fillInStackTrace} and {@link #setStackTrace} will be no-ops,
128      * and {@link #getStackTrace} will return a zero-length array.
129      * @since 1.7
130      */
Throwable(String detailMessage, Throwable cause, boolean enableSuppression, boolean writableStackTrace)131     protected Throwable(String detailMessage, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
132         this.detailMessage = detailMessage;
133         this.cause = cause;
134         if (!enableSuppression) {
135             this.suppressedExceptions = null;
136         }
137         if (writableStackTrace) {
138             this.stackTrace = EmptyArray.STACK_TRACE_ELEMENT;
139             fillInStackTrace();
140         } else {
141             this.stackTrace = null;
142         }
143     }
144 
145     /**
146      * Records the stack trace from the point where this method has been called
147      * to this {@code Throwable}. This method is invoked by the {@code Throwable} constructors.
148      *
149      * <p>This method is public so that code (such as an RPC system) which catches
150      * a {@code Throwable} and then re-throws it can replace the construction-time stack trace
151      * with a stack trace from the location where the exception was re-thrown, by <i>calling</i>
152      * {@code fillInStackTrace}.
153      *
154      * <p>This method is non-final so that non-Java language implementations can disable VM stack
155      * traces for their language. Filling in the stack trace is relatively expensive.
156      * <i>Overriding</i> this method in the root of a language's exception hierarchy allows the
157      * language to avoid paying for something it doesn't need.
158      *
159      * @return this {@code Throwable} instance.
160      */
fillInStackTrace()161     public Throwable fillInStackTrace() {
162         if (stackTrace == null) {
163             return this; // writableStackTrace was false.
164         }
165         // Fill in the intermediate representation.
166         stackState = nativeFillInStackTrace();
167         // Mark the full representation as in need of update.
168         stackTrace = EmptyArray.STACK_TRACE_ELEMENT;
169         return this;
170     }
171 
172     /**
173      * Returns the detail message which was provided when this
174      * {@code Throwable} was created. Returns {@code null} if no message was
175      * provided at creation time.
176      */
getMessage()177     public String getMessage() {
178         return detailMessage;
179     }
180 
181     /**
182      * Returns the detail message which was provided when this
183      * {@code Throwable} was created. Returns {@code null} if no message was
184      * provided at creation time. Subclasses may override this method to return
185      * localized text for the message. Android returns the regular detail message.
186      */
getLocalizedMessage()187     public String getLocalizedMessage() {
188         return getMessage();
189     }
190 
191     /**
192      * Returns a clone of the array of stack trace elements of this {@code Throwable}. Each
193      * {@code StackTraceElement} represents an entry in the call stack. The
194      * element at position 0 is the top of the stack, that is, the stack frame
195      * where this {@code Throwable} is thrown.
196      *
197      * @see #printStackTrace()
198      */
getStackTrace()199     public StackTraceElement[] getStackTrace() {
200         return getInternalStackTrace().clone();
201     }
202 
203     /**
204      * Sets the array of stack trace elements. Each {@code StackTraceElement}
205      * represents an entry in the call stack. A copy of the specified array is
206      * stored in this {@code Throwable}. will be returned by {@code
207      * getStackTrace()} and printed by {@code printStackTrace()}.
208      *
209      * @param trace
210      *            the new array of {@code StackTraceElement}s. A copy of the
211      *            array is stored in this {@code Throwable}, so subsequent
212      *            changes to {@code trace} will not change the call stack stored
213      *            in this {@code Throwable}.
214      * @throws NullPointerException
215      *             if any element in {@code trace} is {@code null}.
216      * @see #printStackTrace()
217      */
setStackTrace(StackTraceElement[] trace)218     public void setStackTrace(StackTraceElement[] trace) {
219         if (stackTrace == null) {
220             return; // writableStackTrace was false.
221         }
222         StackTraceElement[] newTrace = trace.clone();
223         for (int i = 0; i < newTrace.length; i++) {
224             if (newTrace[i] == null) {
225                 throw new NullPointerException("trace[" + i + "] == null");
226             }
227         }
228         stackTrace = newTrace;
229     }
230 
231     /**
232      * Writes a printable representation of this {@code Throwable}'s stack trace
233      * to the {@code System.err} stream.
234      */
printStackTrace()235     public void printStackTrace() {
236         printStackTrace(System.err);
237     }
238 
239     /**
240      * Counts the number of duplicate stack frames, starting from the
241      * end of the stack.
242      */
countDuplicates(StackTraceElement[] currentStack, StackTraceElement[] parentStack)243     private static int countDuplicates(StackTraceElement[] currentStack,
244             StackTraceElement[] parentStack) {
245         int duplicates = 0;
246         int parentIndex = parentStack.length;
247         for (int i = currentStack.length; --i >= 0 && --parentIndex >= 0;) {
248             StackTraceElement parentFrame = parentStack[parentIndex];
249             if (parentFrame.equals(currentStack[i])) {
250                 duplicates++;
251             } else {
252                 break;
253             }
254         }
255         return duplicates;
256     }
257 
258     /**
259      * Returns an array of StackTraceElement. Each StackTraceElement
260      * represents a entry on the stack.
261      */
getInternalStackTrace()262     private StackTraceElement[] getInternalStackTrace() {
263         if (stackTrace == EmptyArray.STACK_TRACE_ELEMENT) {
264             stackTrace = nativeGetStackTrace(stackState);
265             stackState = null; // Let go of intermediate representation.
266             return stackTrace;
267         } else if (stackTrace == null) {
268             return EmptyArray.STACK_TRACE_ELEMENT;
269         } else {
270           return stackTrace;
271         }
272     }
273 
274     /**
275      * Writes a printable representation of this {@code Throwable}'s stack trace
276      * to the given print stream. If the {@code Throwable} contains a
277      * {@link #getCause() cause}, the method will be invoked recursively for
278      * the nested {@code Throwable}.
279      */
printStackTrace(PrintStream err)280     public void printStackTrace(PrintStream err) {
281         try {
282             printStackTrace(err, "", null);
283         } catch (IOException e) {
284             // Appendable.append throws IOException but PrintStream.append doesn't.
285             throw new AssertionError();
286         }
287     }
288 
289     /**
290      * Writes a printable representation of this {@code Throwable}'s stack trace
291      * to the specified print writer. If the {@code Throwable} contains a
292      * {@link #getCause() cause}, the method will be invoked recursively for the
293      * nested {@code Throwable}.
294      *
295      * @param err
296      *            the writer to write the stack trace on.
297      */
printStackTrace(PrintWriter err)298     public void printStackTrace(PrintWriter err) {
299         try {
300             printStackTrace(err, "", null);
301         } catch (IOException e) {
302             // Appendable.append throws IOException, but PrintWriter.append doesn't.
303             throw new AssertionError();
304         }
305     }
306 
307     /**
308      * @param indent additional indentation on each line of the stack trace.
309      *     This is the empty string for all but suppressed throwables.
310      * @param parentStack the parent stack trace to suppress duplicates from, or
311      *     null if this stack trace has no parent.
312      */
printStackTrace(Appendable err, String indent, StackTraceElement[] parentStack)313     private void printStackTrace(Appendable err, String indent, StackTraceElement[] parentStack)
314             throws IOException {
315         err.append(toString());
316         err.append("\n");
317 
318         StackTraceElement[] stack = getInternalStackTrace();
319         if (stack != null) {
320             int duplicates = parentStack != null ? countDuplicates(stack, parentStack) : 0;
321             for (int i = 0; i < stack.length - duplicates; i++) {
322                 err.append(indent);
323                 err.append("\tat ");
324                 err.append(stack[i].toString());
325                 err.append("\n");
326             }
327 
328             if (duplicates > 0) {
329                 err.append(indent);
330                 err.append("\t... ");
331                 err.append(Integer.toString(duplicates));
332                 err.append(" more\n");
333             }
334         }
335 
336         // Print suppressed exceptions indented one level deeper.
337         if (suppressedExceptions != null) {
338             for (Throwable throwable : suppressedExceptions) {
339                 err.append(indent);
340                 err.append("\tSuppressed: ");
341                 throwable.printStackTrace(err, indent + "\t", stack);
342             }
343         }
344 
345         Throwable cause = getCause();
346         if (cause != null) {
347             err.append(indent);
348             err.append("Caused by: ");
349             cause.printStackTrace(err, indent, stack);
350         }
351     }
352 
353     @Override
toString()354     public String toString() {
355         String msg = getLocalizedMessage();
356         String name = getClass().getName();
357         if (msg == null) {
358             return name;
359         }
360         return name + ": " + msg;
361     }
362 
363     /**
364      * Initializes the cause of this {@code Throwable}. The cause can only be
365      * initialized once.
366      *
367      * @param throwable
368      *            the cause of this {@code Throwable}.
369      * @return this {@code Throwable} instance.
370      * @throws IllegalArgumentException
371      *             if {@code Throwable} is this object.
372      * @throws IllegalStateException
373      *             if the cause has already been initialized.
374      */
initCause(Throwable throwable)375     public Throwable initCause(Throwable throwable) {
376         if (cause != this) {
377             throw new IllegalStateException("Cause already initialized");
378         }
379         if (throwable == this) {
380             throw new IllegalArgumentException("throwable == this");
381         }
382         cause = throwable;
383         return this;
384     }
385 
386     /**
387      * Returns the cause of this {@code Throwable}, or {@code null} if there is
388      * no cause.
389      */
getCause()390     public Throwable getCause() {
391         if (cause == this) {
392             return null;
393         }
394         return cause;
395     }
396 
397     /**
398      * Adds {@code throwable} to the list of throwables suppressed by this. The
399      * throwable will included when this exception's stack trace is printed.
400      *
401      * @throws IllegalArgumentException if {@code throwable == this}.
402      * @throws NullPointerException if {@code throwable == null}.
403      * @since 1.7
404      */
addSuppressed(Throwable throwable)405     public final void addSuppressed(Throwable throwable) {
406         if (throwable == this) {
407             throw new IllegalArgumentException("throwable == this");
408         }
409         if (throwable == null) {
410             throw new NullPointerException("throwable == null");
411         }
412         if (suppressedExceptions != null) {
413             // Suppressed exceptions are enabled.
414             if (suppressedExceptions.isEmpty()) {
415                 // Ensure we have somewhere to place suppressed exceptions.
416                 suppressedExceptions = new ArrayList<Throwable>(1);
417             }
418             suppressedExceptions.add(throwable);
419         }
420     }
421 
422     /**
423      * Returns the throwables suppressed by this.
424      *
425      * @since 1.7
426      */
getSuppressed()427     public final Throwable[] getSuppressed() {
428         return (suppressedExceptions != null && !suppressedExceptions.isEmpty())
429                 ? suppressedExceptions.toArray(new Throwable[suppressedExceptions.size()])
430                 : EmptyArray.THROWABLE;
431     }
432 
writeObject(ObjectOutputStream out)433     private void writeObject(ObjectOutputStream out) throws IOException {
434         // Ensure the stackTrace field is initialized.
435         getInternalStackTrace();
436         out.defaultWriteObject();
437     }
438 
readObject(ObjectInputStream in)439     private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
440         in.defaultReadObject();
441 
442         if (suppressedExceptions != null) {
443             // The deserialized list may be unmodifiable, so just create a mutable copy.
444             suppressedExceptions = new ArrayList<Throwable>(suppressedExceptions);
445         }
446     }
447 
448     /*
449      * Creates a compact, VM-specific collection of goodies, suitable for
450      * storing in the "stackState" field, based on the current thread's
451      * call stack.
452      */
nativeFillInStackTrace()453     private static native Object nativeFillInStackTrace();
454 
455     /*
456      * Creates an array of StackTraceElement objects from the data held
457      * in "stackState".
458      */
nativeGetStackTrace(Object stackState)459     private static native StackTraceElement[] nativeGetStackTrace(Object stackState);
460 }
461