1 /* 2 * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.lang; 27 28 import java.util.Objects; 29 30 /** 31 * An element in a stack trace, as returned by {@link 32 * Throwable#getStackTrace()}. Each element represents a single stack frame. 33 * All stack frames except for the one at the top of the stack represent 34 * a method invocation. The frame at the top of the stack represents the 35 * execution point at which the stack trace was generated. Typically, 36 * this is the point at which the throwable corresponding to the stack trace 37 * was created. 38 * 39 * @since 1.4 40 * @author Josh Bloch 41 */ 42 public final class StackTraceElement implements java.io.Serializable { 43 44 // For Throwables and StackWalker, the VM initially sets this field to a 45 // reference to the declaring Class. The Class reference is used to 46 // construct the 'format' bitmap, and then is cleared. 47 // 48 // For STEs constructed using the public constructors, this field is not used. 49 // Android-removed: Remove classloader name and unsupported module name and version. 50 // private transient Class<?> declaringClassObject; 51 52 // Normally initialized by VM 53 // Android-removed: Remove classloader name and unsupported module name and version. 54 // private String classLoaderName; 55 // private String moduleName; 56 // private String moduleVersion; 57 private String declaringClass; 58 private String methodName; 59 private String fileName; 60 private int lineNumber; 61 // Android-removed: Remove classloader name and unsupported module name and version. 62 // private byte format = 0; // Default to show all 63 64 65 // Android-changed: Remove javadoc related the unsupported module name and version. 66 /** 67 * Creates a stack trace element representing the specified execution 68 * point. 69 * 70 * @param declaringClass the fully qualified name of the class containing 71 * the execution point represented by the stack trace element 72 * @param methodName the name of the method containing the execution point 73 * represented by the stack trace element 74 * @param fileName the name of the file containing the execution point 75 * represented by the stack trace element, or {@code null} if 76 * this information is unavailable 77 * @param lineNumber the line number of the source line containing the 78 * execution point represented by this stack trace element, or 79 * a negative number if this information is unavailable. A value 80 * of -2 indicates that the method containing the execution point 81 * is a native method 82 * @throws NullPointerException if {@code declaringClass} or 83 * {@code methodName} is null 84 * @since 1.5 85 * @revised 9 86 * @spec JPMS 87 */ StackTraceElement(String declaringClass, String methodName, String fileName, int lineNumber)88 public StackTraceElement(String declaringClass, String methodName, 89 String fileName, int lineNumber) { 90 // Android-changed: Avoid dependency on module-related codes. 91 // this(null, null, null, declaringClass, methodName, fileName, lineNumber); 92 this.declaringClass = Objects.requireNonNull(declaringClass, "Declaring class is null"); 93 this.methodName = Objects.requireNonNull(methodName, "Method name is null"); 94 this.fileName = fileName; 95 this.lineNumber = lineNumber; 96 } 97 98 // BEGIN Android-removed: Remove module-related methods. 99 /* 100 /** 101 * Creates a stack trace element representing the specified execution 102 * point. 103 * 104 * @param classLoaderName the class loader name if the class loader of 105 * the class containing the execution point represented by 106 * the stack trace is named; otherwise {@code null} 107 * @param moduleName the module name if the class containing the 108 * execution point represented by the stack trace is in a named 109 * module; otherwise {@code null} 110 * @param moduleVersion the module version if the class containing the 111 * execution point represented by the stack trace is in a named 112 * module that has a version; otherwise {@code null} 113 * @param declaringClass the fully qualified name of the class containing 114 * the execution point represented by the stack trace element 115 * @param methodName the name of the method containing the execution point 116 * represented by the stack trace element 117 * @param fileName the name of the file containing the execution point 118 * represented by the stack trace element, or {@code null} if 119 * this information is unavailable 120 * @param lineNumber the line number of the source line containing the 121 * execution point represented by this stack trace element, or 122 * a negative number if this information is unavailable. A value 123 * of -2 indicates that the method containing the execution point 124 * is a native method 125 * 126 * @throws NullPointerException if {@code declaringClass} is {@code null} 127 * or {@code methodName} is {@code null} 128 * 129 * @since 9 130 * @spec JPMS 131 * 132 public StackTraceElement(String classLoaderName, 133 String moduleName, String moduleVersion, 134 String declaringClass, String methodName, 135 String fileName, int lineNumber) { 136 this.classLoaderName = classLoaderName; 137 this.moduleName = moduleName; 138 this.moduleVersion = moduleVersion; 139 this.declaringClass = Objects.requireNonNull(declaringClass, "Declaring class is null"); 140 this.methodName = Objects.requireNonNull(methodName, "Method name is null"); 141 this.fileName = fileName; 142 this.lineNumber = lineNumber; 143 } 144 */ 145 // END Android-removed: Remove module-related methods. 146 147 /* 148 * Private constructor for the factory methods to create StackTraceElement 149 * for Throwable and StackFrameInfo 150 */ StackTraceElement()151 private StackTraceElement() {} 152 153 /** 154 * Returns the name of the source file containing the execution point 155 * represented by this stack trace element. Generally, this corresponds 156 * to the {@code SourceFile} attribute of the relevant {@code class} 157 * file (as per <i>The Java Virtual Machine Specification</i>, Section 158 * 4.7.7). In some systems, the name may refer to some source code unit 159 * other than a file, such as an entry in source repository. 160 * 161 * @return the name of the file containing the execution point 162 * represented by this stack trace element, or {@code null} if 163 * this information is unavailable. 164 */ getFileName()165 public String getFileName() { 166 return fileName; 167 } 168 169 /** 170 * Returns the line number of the source line containing the execution 171 * point represented by this stack trace element. Generally, this is 172 * derived from the {@code LineNumberTable} attribute of the relevant 173 * {@code class} file (as per <i>The Java Virtual Machine 174 * Specification</i>, Section 4.7.8). 175 * 176 * @return the line number of the source line containing the execution 177 * point represented by this stack trace element, or a negative 178 * number if this information is unavailable. 179 */ getLineNumber()180 public int getLineNumber() { 181 return lineNumber; 182 } 183 184 // BEGIN Android-removed: Remove classloader name and module-related methods. 185 /* 186 /** 187 * Returns the module name of the module containing the execution point 188 * represented by this stack trace element. 189 * 190 * @return the module name of the {@code Module} containing the execution 191 * point represented by this stack trace element; {@code null} 192 * if the module name is not available. 193 * @since 9 194 * @spec JPMS 195 * @see Module#getName() 196 * 197 public String getModuleName() { 198 return moduleName; 199 } 200 201 /** 202 * Returns the module version of the module containing the execution point 203 * represented by this stack trace element. 204 * 205 * @return the module version of the {@code Module} containing the execution 206 * point represented by this stack trace element; {@code null} 207 * if the module version is not available. 208 * @since 9 209 * @spec JPMS 210 * @see java.lang.module.ModuleDescriptor.Version 211 * 212 public String getModuleVersion() { 213 return moduleVersion; 214 } 215 216 /** 217 * Returns the name of the class loader of the class containing the 218 * execution point represented by this stack trace element. 219 * 220 * @return the name of the class loader of the class containing the execution 221 * point represented by this stack trace element; {@code null} 222 * if the class loader is not named. 223 * 224 * @since 9 225 * @spec JPMS 226 * @see java.lang.ClassLoader#getName() 227 * 228 public String getClassLoaderName() { 229 return classLoaderName; 230 } 231 */ 232 // END Android-removed: Remove classloader name and module-related methods. 233 234 /** 235 * Returns the fully qualified name of the class containing the 236 * execution point represented by this stack trace element. 237 * 238 * @return the fully qualified name of the {@code Class} containing 239 * the execution point represented by this stack trace element. 240 */ getClassName()241 public String getClassName() { 242 return declaringClass; 243 } 244 245 /** 246 * Returns the name of the method containing the execution point 247 * represented by this stack trace element. If the execution point is 248 * contained in an instance or class initializer, this method will return 249 * the appropriate <i>special method name</i>, {@code <init>} or 250 * {@code <clinit>}, as per Section 3.9 of <i>The Java Virtual 251 * Machine Specification</i>. 252 * 253 * @return the name of the method containing the execution point 254 * represented by this stack trace element. 255 */ getMethodName()256 public String getMethodName() { 257 return methodName; 258 } 259 260 /** 261 * Returns true if the method containing the execution point 262 * represented by this stack trace element is a native method. 263 * 264 * @return {@code true} if the method containing the execution point 265 * represented by this stack trace element is a native method. 266 */ isNativeMethod()267 public boolean isNativeMethod() { 268 return lineNumber == -2; 269 } 270 271 // Android-changed: Remove javadoc related to the module system. 272 /** 273 * Returns a string representation of this stack trace element. 274 * 275 * @apiNote The format of this string depends on the implementation, but the 276 * following examples may be regarded as typical: 277 * <ul> 278 * <li> 279 * {@code "MyClass.mash(MyClass.java:9)"} - Here, {@code "MyClass"} 280 * is the <i>fully-qualified name</i> of the class containing the 281 * execution point represented by this stack trace element, 282 * {@code "mash"} is the name of the method containing the execution 283 * point, {@code "MyClass.java"} is the source file containing the 284 * execution point, and {@code "9"} is the line number of the source 285 * line containing the execution point. 286 * <li> 287 * {@code "MyClass.mash(MyClass.java)"} - As above, but the line 288 * number is unavailable. 289 * <li> 290 * {@code "MyClass.mash(Unknown Source)"} - As above, but neither 291 * the file name nor the line number are available. 292 * <li> 293 * {@code "MyClass.mash(Native Method)"} - As above, but neither 294 * the file name nor the line number are available, and the method 295 * containing the execution point is known to be a native method. 296 * </ul> 297 * 298 * <p> The {@code toString} method may return two different values on two 299 * {@code StackTraceElement} instances that are 300 * {@linkplain #equals(Object) equal}, for example one created via the 301 * constructor, and one obtained from {@link java.lang.Throwable} or 302 * {@link java.lang.StackWalker.StackFrame}, where an implementation may 303 * choose to omit some element in the returned string. 304 * 305 * @revised 9 306 * @spec JPMS 307 * @see Throwable#printStackTrace() 308 */ toString()309 public String toString() { 310 // BEGIN Android-changed: Fall back Unknown Source:<dex_pc> for unknown lineNumber. 311 // http://b/30183883 312 // The only behavior change is that "Unknown Source" is followed by a number 313 // (the value of the dex program counter, dex_pc), which never occurs on the 314 // RI. This value isn't a line number, but can be useful for debugging and 315 // avoids the need to ship line number information along with the dex code to 316 // get an accurate stack trace. 317 // Formatting it in this way might be more digestible to automated tools that 318 // are not specifically written to expect this behavior. 319 /* 320 String s = ""; 321 if (!dropClassLoaderName() && classLoaderName != null && 322 !classLoaderName.isEmpty()) { 323 s += classLoaderName + "/"; 324 } 325 if (moduleName != null && !moduleName.isEmpty()) { 326 s += moduleName; 327 328 if (!dropModuleVersion() && moduleVersion != null && 329 !moduleVersion.isEmpty()) { 330 s += "@" + moduleVersion; 331 } 332 } 333 s = s.isEmpty() ? declaringClass : s + "/" + declaringClass; 334 335 return s + "." + methodName + "(" + 336 (isNativeMethod() ? "Native Method)" : 337 (fileName != null && lineNumber >= 0 ? 338 fileName + ":" + lineNumber + ")" : 339 (fileName != null ? ""+fileName+")" : "Unknown Source)"))); 340 */ 341 StringBuilder result = new StringBuilder(); 342 result.append(getClassName()).append(".").append(methodName); 343 if (isNativeMethod()) { 344 result.append("(Native Method)"); 345 } else if (fileName != null) { 346 if (lineNumber >= 0) { 347 result.append("(").append(fileName).append(":").append(lineNumber).append(")"); 348 } else { 349 result.append("(").append(fileName).append(")"); 350 } 351 } else { 352 if (lineNumber >= 0) { 353 // The line number is actually the dex pc. 354 result.append("(Unknown Source:").append(lineNumber).append(")"); 355 } else { 356 result.append("(Unknown Source)"); 357 } 358 } 359 return result.toString(); 360 // END Android-changed: Fall back Unknown Source:<dex_pc> for unknown lineNumber. 361 } 362 363 // Android-changed: Remove javadoc related to the module system. 364 /** 365 * Returns true if the specified object is another 366 * {@code StackTraceElement} instance representing the same execution 367 * point as this instance. Two stack trace elements {@code a} and 368 * {@code b} are equal if and only if: 369 * <pre>{@code 370 * equals(a.getFileName(), b.getFileName()) && 371 * a.getLineNumber() == b.getLineNumber()) && 372 * equals(a.getClassName(), b.getClassName()) && 373 * equals(a.getMethodName(), b.getMethodName()) 374 * }</pre> 375 * where {@code equals} has the semantics of {@link 376 * java.util.Objects#equals(Object, Object) Objects.equals}. 377 * 378 * @param obj the object to be compared with this stack trace element. 379 * @return true if the specified object is another 380 * {@code StackTraceElement} instance representing the same 381 * execution point as this instance. 382 * 383 * @revised 9 384 * @spec JPMS 385 */ equals(Object obj)386 public boolean equals(Object obj) { 387 if (obj==this) 388 return true; 389 if (!(obj instanceof StackTraceElement)) 390 return false; 391 StackTraceElement e = (StackTraceElement)obj; 392 // Android-changed: Remove classloader name and module-related methods. 393 // return Objects.equals(classLoaderName, e.classLoaderName) && 394 // Objects.equals(moduleName, e.moduleName) && 395 // Objects.equals(moduleVersion, e.moduleVersion) && 396 return 397 e.declaringClass.equals(declaringClass) && 398 e.lineNumber == lineNumber && 399 Objects.equals(methodName, e.methodName) && 400 Objects.equals(fileName, e.fileName); 401 } 402 403 /** 404 * Returns a hash code value for this stack trace element. 405 */ hashCode()406 public int hashCode() { 407 int result = 31*declaringClass.hashCode() + methodName.hashCode(); 408 // Android-changed: Remove classloader name and module-related methods. 409 // result = 31*result + Objects.hashCode(classLoaderName); 410 // result = 31*result + Objects.hashCode(moduleName); 411 // result = 31*result + Objects.hashCode(moduleVersion); 412 result = 31*result + Objects.hashCode(fileName); 413 result = 31*result + lineNumber; 414 return result; 415 } 416 417 418 // BEGIN Android-removed: Remove classloader name and unsupported module name and version. 419 /* 420 /** 421 * Called from of() methods to set the 'format' bitmap using the Class 422 * reference stored in declaringClassObject, and then clear the reference. 423 * 424 * <p> 425 * If the module is a non-upgradeable JDK module, then set 426 * JDK_NON_UPGRADEABLE_MODULE to omit its version string. 427 * <p> 428 * If the loader is one of the built-in loaders (`boot`, `platform`, or `app`) 429 * then set BUILTIN_CLASS_LOADER to omit the first element (`<loader>/`). 430 * 431 private synchronized void computeFormat() { 432 try { 433 Class<?> cls = (Class<?>) declaringClassObject; 434 ClassLoader loader = cls.getClassLoader0(); 435 Module m = cls.getModule(); 436 byte bits = 0; 437 438 // First element - class loader name 439 // Call package-private ClassLoader::name method 440 441 if (loader instanceof BuiltinClassLoader) { 442 bits |= BUILTIN_CLASS_LOADER; 443 } 444 445 // Second element - module name and version 446 447 // Omit if is a JDK non-upgradeable module (recorded in the hashes 448 // in java.base) 449 if (isHashedInJavaBase(m)) { 450 bits |= JDK_NON_UPGRADEABLE_MODULE; 451 } 452 format = bits; 453 } finally { 454 // Class reference no longer needed, clear it 455 declaringClassObject = null; 456 } 457 } 458 459 private static final byte BUILTIN_CLASS_LOADER = 0x1; 460 private static final byte JDK_NON_UPGRADEABLE_MODULE = 0x2; 461 462 private boolean dropClassLoaderName() { 463 return (format & BUILTIN_CLASS_LOADER) == BUILTIN_CLASS_LOADER; 464 } 465 466 private boolean dropModuleVersion() { 467 return (format & JDK_NON_UPGRADEABLE_MODULE) == JDK_NON_UPGRADEABLE_MODULE; 468 } 469 470 /** 471 * Returns true if the module is hashed with java.base. 472 * <p> 473 * This method returns false when running on the exploded image 474 * since JDK modules are not hashed. They have no Version attribute 475 * and so "@<version>" part will be omitted anyway. 476 * 477 private static boolean isHashedInJavaBase(Module m) { 478 // return true if module system is not initialized as the code 479 // must be in java.base 480 if (!VM.isModuleSystemInited()) 481 return true; 482 483 return ModuleLayer.boot() == m.getLayer() && HashedModules.contains(m); 484 } 485 486 /* 487 * Finds JDK non-upgradeable modules, i.e. the modules that are 488 * included in the hashes in java.base. 489 * 490 private static class HashedModules { 491 static Set<String> HASHED_MODULES = hashedModules(); 492 493 static Set<String> hashedModules() { 494 495 Optional<ResolvedModule> resolvedModule = ModuleLayer.boot() 496 .configuration() 497 .findModule("java.base"); 498 assert resolvedModule.isPresent(); 499 ModuleReference mref = resolvedModule.get().reference(); 500 assert mref instanceof ModuleReferenceImpl; 501 ModuleHashes hashes = ((ModuleReferenceImpl)mref).recordedHashes(); 502 if (hashes != null) { 503 Set<String> names = new HashSet<>(hashes.names()); 504 names.add("java.base"); 505 return names; 506 } 507 508 return Set.of(); 509 } 510 511 static boolean contains(Module m) { 512 return HASHED_MODULES.contains(m.getName()); 513 } 514 } 515 */ 516 // END Android-removed: Remove classloader name and unsupported module name and version. 517 518 // BEGIN Android-removed: code unused by Throwable in libcore. 519 /* 520 * Returns an array of StackTraceElements of the given depth 521 * filled from the backtrace of a given Throwable. 522 * 523 static StackTraceElement[] of(Throwable x, int depth) { 524 StackTraceElement[] stackTrace = new StackTraceElement[depth]; 525 for (int i = 0; i < depth; i++) { 526 stackTrace[i] = new StackTraceElement(); 527 } 528 529 // VM to fill in StackTraceElement 530 initStackTraceElements(stackTrace, x); 531 532 // ensure the proper StackTraceElement initialization 533 for (StackTraceElement ste : stackTrace) { 534 ste.computeFormat(); 535 } 536 return stackTrace; 537 } 538 */ 539 // END Android-removed: code unused by Throwable in libcore. 540 541 /* 542 * Returns a StackTraceElement from a given StackFrameInfo. 543 */ of(StackFrameInfo sfi)544 static StackTraceElement of(StackFrameInfo sfi) { 545 // Android-changed: Simple java implementation without module name. 546 // StackTraceElement ste = new StackTraceElement(); 547 // initStackTraceElement(ste, sfi); 548 StackTraceElement ste = new StackTraceElement(sfi.getClassName(), sfi.getMethodName(), 549 sfi.getFileName(), sfi.getLineNumber()); 550 551 // Android-removed: Remove classloader name and unsupported module name and version. 552 // ste.computeFormat(); 553 return ste; 554 } 555 556 /* 557 * Sets the given stack trace elements with the backtrace 558 * of the given Throwable. 559 */ 560 // Android-removed: code unused by Throwable in libcore. 561 // private static native void initStackTraceElements(StackTraceElement[] elements, 562 // Throwable x); 563 564 /* 565 * Sets the given stack trace element with the given StackFrameInfo 566 */ 567 // Android-removed: unused dead code. 568 // private static native void initStackTraceElement(StackTraceElement element, 569 // StackFrameInfo sfi); 570 571 private static final long serialVersionUID = 6992337162326171013L; 572 } 573