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.ObjectOutputStream;
22import java.io.PrintStream;
23import java.io.PrintWriter;
24
25/**
26 * The superclass of all classes which can be thrown by the virtual machine. The
27 * two direct subclasses are recoverable exceptions ({@code Exception}) and
28 * unrecoverable errors ({@code Error}). This class provides common methods for
29 * accessing a string message which provides extra information about the
30 * circumstances in which the {@code Throwable} was created (basically an error
31 * message in most cases), and for saving a stack trace (that is, a record of
32 * the call stack at a particular point in time) which can be printed later.
33 * <p>
34 * A {@code Throwable} can also include a cause, which is a nested {@code
35 * Throwable} that represents the original problem that led to this {@code
36 * Throwable}. It is often used for wrapping various types of errors into a
37 * common {@code Throwable} without losing the detailed original error
38 * information. When printing the stack trace, the trace of the cause is
39 * included.
40 *
41 * @see Error
42 * @see Exception
43 * @see RuntimeException
44 *
45 * @since Android 1.0
46 */
47public class Throwable implements java.io.Serializable {
48    private static final long serialVersionUID = -3042686055658047285L;
49
50    /**
51     * The message provided when the exception was created.
52     */
53    private String detailMessage;
54
55    /**
56     * The cause of this Throwable. Null when there is no cause.
57     */
58    private Throwable cause = this;
59
60    // BEGIN android-added
61    /**
62     * An intermediate representation of the stack trace.  This field may
63     * be accessed by the VM; do not rename.
64     */
65    private volatile Object stackState;
66    // END android-added
67
68    /**
69     * A fully-expanded representation of the stack trace.
70     */
71    private StackTraceElement[] stackTrace;
72
73    /**
74     * Constructs a new {@code Throwable} that includes the current stack trace.
75     *
76     * @since Android 1.0
77     */
78    public Throwable() {
79        super();
80        fillInStackTrace();
81    }
82
83    /**
84     * Constructs a new {@code Throwable} with the current stack trace and the
85     * specified detail message.
86     *
87     * @param detailMessage
88     *            the detail message for this {@code Throwable}.
89     * @since Android 1.0
90     */
91    public Throwable(String detailMessage) {
92        this();
93        this.detailMessage = detailMessage;
94    }
95
96    /**
97     * Constructs a new {@code Throwable} with the current stack trace, the
98     * specified detail message and the specified cause.
99     *
100     * @param detailMessage
101     *            the detail message for this {@code Throwable}.
102     * @param throwable
103     *            the cause of this {@code Throwable}.
104     * @since Android 1.0
105     */
106    public Throwable(String detailMessage, Throwable throwable) {
107        this();
108        this.detailMessage = detailMessage;
109        cause = throwable;
110    }
111
112    /**
113     * Constructs a new {@code Throwable} with the current stack trace and the
114     * specified cause.
115     *
116     * @param throwable
117     *            the cause of this {@code Throwable}.
118     * @since Android 1.0
119     */
120    public Throwable(Throwable throwable) {
121        this();
122        this.detailMessage = throwable == null ? null : throwable.toString();
123        cause = throwable;
124    }
125
126    // BEGIN android-changed
127    /**
128     * Records the stack trace from the point where this method has been called
129     * to this {@code Throwable}. The method is public so that code which
130     * catches a {@code Throwable} and then re-throws it can adjust the stack
131     * trace to represent the location where the exception was re-thrown.
132     *
133     * @return this {@code Throwable} instance.
134     * @since Android 1.0
135     */
136    public Throwable fillInStackTrace() {
137        // Fill in the intermediate representation
138        stackState = nativeFillInStackTrace();
139        // Mark the full representation as empty
140        stackTrace = null;
141        return this;
142    }
143    // END android-changed
144
145    /**
146     * Returns the extra information message which was provided when this
147     * {@code Throwable} was created. Returns {@code null} if no message was
148     * provided at creation time.
149     *
150     * @return this {@code Throwable}'s detail message.
151     * @since Android 1.0
152     */
153    public String getMessage() {
154        return detailMessage;
155    }
156
157    /**
158     * Returns the extra information message which was provided when this
159     * {@code Throwable} was created. Returns {@code null} if no message was
160     * provided at creation time. Subclasses may override this method to return
161     * localized text for the message. The Android reference implementation
162     * returns the unlocalized detail message.
163     *
164     * @return this {@code Throwable}'s localized detail message.
165     * @since Android 1.0
166     */
167    public String getLocalizedMessage() {
168        return getMessage();
169    }
170
171    /**
172     * Returns the array of stack trace elements of this {@code Throwable}. Each
173     * {@code StackTraceElement} represents an entry in the call stack. The
174     * element at position 0 is the top of the stack, that is, the stack frame
175     * where this {@code Throwable} is thrown.
176     *
177     * @return a copy of the array of {@code StackTraceElement}s representing
178     *         the call stack. Changes in the array obtained from this call will
179     *         not change the call stack stored in this {@code Throwable}.
180     * @see #printStackTrace()
181     * @since Android 1.0
182     */
183    public StackTraceElement[] getStackTrace() {
184        return getInternalStackTrace().clone();
185    }
186
187    /**
188     * Sets the array of stack trace elements. Each {@code StackTraceElement}
189     * represents an entry in the call stack. A copy of the specified array is
190     * stored in this {@code Throwable}. will be returned by {@code
191     * getStackTrace()} and printed by {@code printStackTrace()}.
192     *
193     * @param trace
194     *            the new array of {@code StackTraceElement}s. A copy of the
195     *            array is stored in this {@code Throwable}, so subsequent
196     *            changes to {@code trace} will not change the call stack stored
197     *            in this {@code Throwable}.
198     * @throws NullPointerException
199     *             if any element in {@code trace} is {@code null}.
200     * @see #printStackTrace()
201     * @since Android 1.0
202     */
203    public void setStackTrace(StackTraceElement[] trace) {
204        StackTraceElement[] newTrace = trace.clone();
205        for (java.lang.StackTraceElement element : newTrace) {
206            if (element == null) {
207                throw new NullPointerException();
208            }
209        }
210        stackTrace = newTrace;
211    }
212
213    /**
214     * Writes a printable representation of this {@code Throwable}'s stack trace
215     * to the {@code System.err} stream.
216     *
217     * @since Android 1.0
218     */
219    public void printStackTrace() {
220        printStackTrace(System.err);
221    }
222
223    /**
224     * Counts the number of duplicate stack frames, starting from the
225     * end of the stack.
226     *
227     * @param currentStack a stack to compare
228     * @param parentStack a stack to compare
229     *
230     * @return the number of duplicate stack frames.
231     */
232    private static int countDuplicates(StackTraceElement[] currentStack,
233            StackTraceElement[] parentStack) {
234        int duplicates = 0;
235        int parentIndex = parentStack.length;
236        for (int i = currentStack.length; --i >= 0 && --parentIndex >= 0;) {
237            StackTraceElement parentFrame = parentStack[parentIndex];
238            if (parentFrame.equals(currentStack[i])) {
239                duplicates++;
240            } else {
241                break;
242            }
243        }
244        return duplicates;
245    }
246
247    /**
248     * Returns an array of StackTraceElement. Each StackTraceElement
249     * represents a entry on the stack.
250     *
251     * @return an array of StackTraceElement representing the stack
252     */
253    private StackTraceElement[] getInternalStackTrace() {
254        if (stackTrace == null) {
255            // BEGIN android-changed
256            stackTrace = nativeGetStackTrace(stackState);
257            stackState = null; // Clean up intermediate representation
258            // END android-changed
259        }
260        return stackTrace;
261    }
262
263    /**
264     * Writes a printable representation of this {@code Throwable}'s stack trace
265     * to the specified print stream. If the {@code Throwable} contains a
266     * {@link #getCause() cause}, the method will be invoked recursively for
267     * the nested {@code Throwable}.
268     *
269     * @param err
270     *            the stream to write the stack trace on.
271     * @since Android 1.0
272     */
273    public void printStackTrace(PrintStream err) {
274        err.println(toString());
275        // Don't use getStackTrace() as it calls clone()
276        // Get stackTrace, in case stackTrace is reassigned
277        StackTraceElement[] stack = getInternalStackTrace();
278        for (java.lang.StackTraceElement element : stack) {
279            err.println("\tat " + element);
280        }
281
282        StackTraceElement[] parentStack = stack;
283        Throwable throwable = getCause();
284        while (throwable != null) {
285            err.print("Caused by: ");
286            err.println(throwable);
287            StackTraceElement[] currentStack = throwable.getInternalStackTrace();
288            int duplicates = countDuplicates(currentStack, parentStack);
289            for (int i = 0; i < currentStack.length - duplicates; i++) {
290                err.println("\tat " + currentStack[i]);
291            }
292            if (duplicates > 0) {
293                err.println("\t... " + duplicates + " more");
294            }
295            parentStack = currentStack;
296            throwable = throwable.getCause();
297        }
298    }
299
300    /**
301     * Writes a printable representation of this {@code Throwable}'s stack trace
302     * to the specified print writer. If the {@code Throwable} contains a
303     * {@link #getCause() cause}, the method will be invoked recursively for the
304     * nested {@code Throwable}.
305     *
306     * @param err
307     *            the writer to write the stack trace on.
308     * @since Android 1.0
309     */
310    public void printStackTrace(PrintWriter err) {
311        err.println(toString());
312        // Don't use getStackTrace() as it calls clone()
313        // Get stackTrace, in case stackTrace is reassigned
314        StackTraceElement[] stack = getInternalStackTrace();
315        for (java.lang.StackTraceElement element : stack) {
316            err.println("\tat " + element);
317        }
318
319        StackTraceElement[] parentStack = stack;
320        Throwable throwable = getCause();
321        while (throwable != null) {
322            err.print("Caused by: ");
323            err.println(throwable);
324            StackTraceElement[] currentStack = throwable.getInternalStackTrace();
325            int duplicates = countDuplicates(currentStack, parentStack);
326            for (int i = 0; i < currentStack.length - duplicates; i++) {
327                err.println("\tat " + currentStack[i]);
328            }
329            if (duplicates > 0) {
330                err.println("\t... " + duplicates + " more");
331            }
332            parentStack = currentStack;
333            throwable = throwable.getCause();
334        }
335    }
336
337    @Override
338    public String toString() {
339        String msg = getLocalizedMessage();
340        String name = getClass().getName();
341        if (msg == null) {
342            return name;
343        }
344        return new StringBuffer(name.length() + 2 + msg.length()).append(name).append(": ")
345                .append(msg).toString();
346    }
347
348    /**
349     * Initializes the cause of this {@code Throwable}. The cause can only be
350     * initialized once.
351     *
352     * @param throwable
353     *            the cause of this {@code Throwable}.
354     * @return this {@code Throwable} instance.
355     * @throws IllegalArgumentException
356     *             if {@code Throwable} is this object.
357     * @throws IllegalStateException
358     *             if the cause has already been initialized.
359     * @since Android 1.0
360     */
361    public Throwable initCause(Throwable throwable) {
362        // BEGIN android-note
363        // removed synchronized modifier
364        // END android-note
365        if (cause == this) {
366            if (throwable != this) {
367                cause = throwable;
368                return this;
369            }
370            throw new IllegalArgumentException("Cause cannot be the receiver");
371        }
372        throw new IllegalStateException("Cause already initialized");
373    }
374
375    /**
376     * Returns the cause of this {@code Throwable}, or {@code null} if there is
377     * no cause.
378     *
379     * @return Throwable this {@code Throwable}'s cause.
380     * @since Android 1.0
381     */
382    public Throwable getCause() {
383        if (cause == this) {
384            return null;
385        }
386        return cause;
387    }
388
389    private void writeObject(ObjectOutputStream s) throws IOException {
390        // ensure the stackTrace field is initialized
391        getInternalStackTrace();
392        s.defaultWriteObject();
393    }
394
395    // BEGIN android-added
396    /*
397     * Creates a compact, VM-specific collection of goodies, suitable for
398     * storing in the "stackState" field, based on the current thread's
399     * call stack.
400     */
401    native private static Object nativeFillInStackTrace();
402
403    /*
404     * Creates an array of StackTraceElement objects from the data held
405     * in "stackState".
406     */
407    native private static StackTraceElement[] nativeGetStackTrace(Object stackState);
408    // END android-added
409}
410
411