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