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
18package java.lang;
19
20import java.io.IOException;
21import java.io.ObjectInputStream;
22import java.io.ObjectOutputStream;
23import java.io.PrintStream;
24import java.io.PrintWriter;
25import java.util.ArrayList;
26import java.util.Collections;
27import java.util.List;
28import 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 */
50public 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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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
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     */
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     */
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     */
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     */
427    public final Throwable[] getSuppressed() {
428        return (suppressedExceptions != null && !suppressedExceptions.isEmpty())
429                ? suppressedExceptions.toArray(new Throwable[suppressedExceptions.size()])
430                : EmptyArray.THROWABLE;
431    }
432
433    private void writeObject(ObjectOutputStream out) throws IOException {
434        // Ensure the stackTrace field is initialized.
435        getInternalStackTrace();
436        out.defaultWriteObject();
437    }
438
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     */
453    private static native Object nativeFillInStackTrace();
454
455    /*
456     * Creates an array of StackTraceElement objects from the data held
457     * in "stackState".
458     */
459    private static native StackTraceElement[] nativeGetStackTrace(Object stackState);
460}
461