1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package dalvik.system; 18 19 import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; 20 21 import android.annotation.SystemApi; 22 import android.annotation.TestApi; 23 import android.compat.annotation.ChangeId; 24 import android.compat.annotation.EnabledAfter; 25 import android.compat.annotation.UnsupportedAppUsage; 26 import android.system.ErrnoException; 27 28 import dalvik.annotation.compat.VersionCodes; 29 import dalvik.annotation.optimization.ReachabilitySensitive; 30 31 import libcore.io.Libcore; 32 import libcore.util.NonNull; 33 import libcore.util.Nullable; 34 35 import java.io.File; 36 import java.io.FileNotFoundException; 37 import java.io.IOException; 38 import java.nio.ByteBuffer; 39 import java.util.Arrays; 40 import java.util.Enumeration; 41 import java.util.List; 42 43 /** 44 * Loads DEX files. This class is meant for internal use and should not be used by applications. 45 * 46 * Applications should not instantiate this class. It will hurt performance in most cases and will 47 * lead to incorrect execution of bytecode in the worst case. Applications should use one of the 48 * standard classloaders such as {@link dalvik.system.PathClassLoader} instead. <b>Non-static APIs 49 * will be removed in a future Android release</b>. 50 */ 51 public final class DexFile { 52 /** 53 * If close is called, mCookie becomes null but the internal cookie is preserved if the close 54 * failed so that we can free resources in the finalizer. 55 */ 56 @UnsupportedAppUsage 57 @ReachabilitySensitive 58 private Object mCookie; 59 60 @UnsupportedAppUsage 61 private Object mInternalCookie; 62 @UnsupportedAppUsage 63 private final String mFileName; 64 65 /** 66 * Enforce the file passed to open DexFile to be set as read-only for apps targeting U+. This 67 * is to prevent files to be dynamically loaded being unexpectedly overwritten by 68 * malicious actors. 69 * 70 * @hide 71 */ 72 // TODO (topjohnwu@): change to @EnabledSince with U API version 73 @TestApi 74 @ChangeId 75 @EnabledAfter(targetSdkVersion = VersionCodes.TIRAMISU) 76 public static final long ENFORCE_READ_ONLY_JAVA_DCL = 218865702; 77 78 /** 79 * Opens a DEX file from a given File object. 80 * 81 * @deprecated Applications should use one of the standard classloaders such 82 * as {@link dalvik.system.PathClassLoader} instead. <b>This API will be removed 83 * in a future Android release</b>. 84 */ 85 @Deprecated DexFile(File file)86 public DexFile(File file) throws IOException { 87 this(file.getPath()); 88 } 89 /* 90 * Private version with class loader argument. 91 * 92 * @param file 93 * the File object referencing the actual DEX file 94 * @param loader 95 * the class loader object creating the DEX file object 96 * @param elements 97 * the temporary dex path list elements from DexPathList.makeElements 98 */ DexFile(File file, ClassLoader loader, DexPathList.Element[] elements)99 DexFile(File file, ClassLoader loader, DexPathList.Element[] elements) 100 throws IOException { 101 this(file.getPath(), loader, elements); 102 } 103 104 /** 105 * Opens a DEX file from a given filename. 106 * 107 * @deprecated Applications should use one of the standard classloaders such 108 * as {@link dalvik.system.PathClassLoader} instead. <b>This API will be removed 109 * in a future Android release</b>. 110 */ 111 @Deprecated DexFile(String fileName)112 public DexFile(String fileName) throws IOException { 113 this(fileName, null, null); 114 } 115 116 /* 117 * Private version with class loader argument. 118 * 119 * @param fileName 120 * the filename of the DEX file 121 * @param loader 122 * the class loader creating the DEX file object 123 * @param elements 124 * the temporary dex path list elements from DexPathList.makeElements 125 */ DexFile(String fileName, ClassLoader loader, DexPathList.Element[] elements)126 DexFile(String fileName, ClassLoader loader, DexPathList.Element[] elements) 127 throws IOException { 128 mCookie = openDexFile(fileName, null, 0, loader, elements); 129 mInternalCookie = mCookie; 130 mFileName = fileName; 131 //System.out.println("DEX FILE cookie is " + mCookie + " fileName=" + fileName); 132 } 133 DexFile(ByteBuffer[] bufs, ClassLoader loader, DexPathList.Element[] elements)134 DexFile(ByteBuffer[] bufs, ClassLoader loader, DexPathList.Element[] elements) 135 throws IOException { 136 mCookie = openInMemoryDexFiles(bufs, loader, elements); 137 mInternalCookie = mCookie; 138 mFileName = null; 139 } 140 141 /** 142 * Opens a DEX file from a given filename, using a specified file 143 * to hold the optimized data. 144 * 145 * @param sourceName 146 * Jar or APK file with "classes.dex". 147 * @param outputName 148 * File that will hold the optimized form of the DEX data. 149 * @param flags 150 * Enable optional features. 151 * @param loader 152 * The class loader creating the DEX file object. 153 * @param elements 154 * The temporary dex path list elements from DexPathList.makeElements 155 */ DexFile(String sourceName, String outputName, int flags, ClassLoader loader, DexPathList.Element[] elements)156 private DexFile(String sourceName, String outputName, int flags, ClassLoader loader, 157 DexPathList.Element[] elements) throws IOException { 158 if (outputName != null) { 159 try { 160 String parent = new File(outputName).getParent(); 161 if (Libcore.os.getuid() != Libcore.os.stat(parent).st_uid) { 162 throw new IllegalArgumentException("Optimized data directory " + parent 163 + " is not owned by the current user. Shared storage cannot protect" 164 + " your application from code injection attacks."); 165 } 166 } catch (ErrnoException ignored) { 167 // assume we'll fail with a more contextual error later 168 } 169 } 170 171 mCookie = openDexFile(sourceName, outputName, flags, loader, elements); 172 mInternalCookie = mCookie; 173 mFileName = sourceName; 174 //System.out.println("DEX FILE cookie is " + mCookie + " sourceName=" + sourceName + " outputName=" + outputName); 175 } 176 177 /** 178 * Open a DEX file, specifying the file in which the optimized DEX 179 * data should be written. If the optimized form exists and appears 180 * to be current, it will be used; if not, the VM will attempt to 181 * regenerate it. 182 * 183 * @deprecated Applications should use one of the standard classloaders such 184 * as {@link dalvik.system.PathClassLoader} instead. <b>This API will be removed 185 * in a future Android release</b>. 186 */ 187 @Deprecated loadDex(String sourcePathName, String outputPathName, int flags)188 static public DexFile loadDex(String sourcePathName, String outputPathName, 189 int flags) throws IOException { 190 191 /* 192 * TODO: we may want to cache previously-opened DexFile objects. 193 * The cache would be synchronized with close(). This would help 194 * us avoid mapping the same DEX more than once when an app 195 * decided to open it multiple times. In practice this may not 196 * be a real issue. 197 */ 198 return loadDex(sourcePathName, outputPathName, flags, null, null); 199 } 200 201 /* 202 * Private version of loadDex that also takes a class loader. 203 * 204 * @param sourcePathName 205 * Jar or APK file with "classes.dex". (May expand this to include 206 * "raw DEX" in the future.) 207 * @param outputPathName 208 * File that will hold the optimized form of the DEX data. 209 * @param flags 210 * Enable optional features. (Currently none defined.) 211 * @param loader 212 * Class loader that is aloading the DEX file. 213 * @param elements 214 * The temporary dex path list elements from DexPathList.makeElements 215 * @return 216 * A new or previously-opened DexFile. 217 * @throws IOException 218 * If unable to open the source or output file. 219 */ 220 @UnsupportedAppUsage loadDex(String sourcePathName, String outputPathName, int flags, ClassLoader loader, DexPathList.Element[] elements)221 static DexFile loadDex(String sourcePathName, String outputPathName, 222 int flags, ClassLoader loader, DexPathList.Element[] elements) throws IOException { 223 224 /* 225 * TODO: we may want to cache previously-opened DexFile objects. 226 * The cache would be synchronized with close(). This would help 227 * us avoid mapping the same DEX more than once when an app 228 * decided to open it multiple times. In practice this may not 229 * be a real issue. 230 */ 231 return new DexFile(sourcePathName, outputPathName, flags, loader, elements); 232 } 233 234 /** 235 * Gets the name of the (already opened) DEX file. 236 * 237 * @return the file name 238 * 239 * @deprecated Applications should use one of the standard classloaders such 240 * as {@link dalvik.system.PathClassLoader} instead. <b>This API will be removed 241 * in a future Android release</b>. 242 */ 243 @Deprecated getName()244 public String getName() { 245 return mFileName; 246 } 247 toString()248 @Override public String toString() { 249 if (mFileName != null) { 250 return getName(); 251 } else { 252 return "InMemoryDexFile[cookie=" + Arrays.toString((long[]) mCookie) + "]"; 253 } 254 } 255 256 /** 257 * Closes the DEX file. 258 * <p> 259 * This may not be able to release all of the resources. If classes from this DEX file are 260 * still resident, the DEX file can't be unmapped. In the case where we do not release all 261 * the resources, close is called again in the finalizer. 262 * 263 * @throws IOException 264 * if an I/O error occurs during closing the file, which 265 * normally should not happen 266 * 267 * @deprecated Applications should use one of the standard classloaders such 268 * as {@link dalvik.system.PathClassLoader} instead. <b>This API will be removed 269 * in a future Android release</b>. 270 */ 271 @Deprecated close()272 public void close() throws IOException { 273 if (mInternalCookie != null) { 274 if (closeDexFile(mInternalCookie)) { 275 mInternalCookie = null; 276 } 277 mCookie = null; 278 } 279 } 280 281 /** 282 * Loads a class. Returns the class on success, or a {@code null} reference 283 * on failure. 284 * <p> 285 * If you are not calling this from a class loader, this is most likely not 286 * going to do what you want. Use {@link Class#forName(String)} instead. 287 * <p> 288 * The method does not throw {@link ClassNotFoundException} if the class 289 * isn't found because it isn't reasonable to throw exceptions wildly every 290 * time a class is not found in the first DEX file we look at. 291 * 292 * @param name 293 * the class name, which should look like "java/lang/String" 294 * 295 * @param loader 296 * the class loader that tries to load the class (in most cases 297 * the caller of the method 298 * 299 * @return the {@link Class} object representing the class, or {@code null} 300 * if the class cannot be loaded 301 * 302 * @deprecated Applications should use one of the standard classloaders such 303 * as {@link dalvik.system.PathClassLoader} instead. <b>This API will be removed 304 * in a future Android release</b>. 305 */ 306 @Deprecated loadClass(String name, ClassLoader loader)307 public Class loadClass(String name, ClassLoader loader) { 308 String slashName = name.replace('.', '/'); 309 return loadClassBinaryName(slashName, loader, null); 310 } 311 312 /** 313 * See {@link #loadClass(String, ClassLoader)}. 314 * 315 * This takes a "binary" class name to better match ClassLoader semantics. 316 * 317 * @hide 318 */ 319 @UnsupportedAppUsage loadClassBinaryName(String name, ClassLoader loader, List<Throwable> suppressed)320 public Class loadClassBinaryName(String name, ClassLoader loader, List<Throwable> suppressed) { 321 return defineClass(name, loader, mCookie, this, suppressed); 322 } 323 defineClass(String name, ClassLoader loader, Object cookie, DexFile dexFile, List<Throwable> suppressed)324 private static Class defineClass(String name, ClassLoader loader, Object cookie, 325 DexFile dexFile, List<Throwable> suppressed) { 326 Class result = null; 327 try { 328 result = defineClassNative(name, loader, cookie, dexFile); 329 } catch (NoClassDefFoundError e) { 330 if (suppressed != null) { 331 suppressed.add(e); 332 } 333 } catch (ClassNotFoundException e) { 334 if (suppressed != null) { 335 suppressed.add(e); 336 } 337 } 338 return result; 339 } 340 341 /** 342 * Enumerate the names of the classes in this DEX file. 343 * 344 * @return an enumeration of names of classes contained in the DEX file, in 345 * the usual internal form (like "java/lang/String"). 346 * 347 * @deprecated Applications should use one of the standard classloaders such 348 * as {@link dalvik.system.PathClassLoader} instead. <b>This API will be removed 349 * in a future Android release</b>. 350 */ 351 @Deprecated entries()352 public Enumeration<String> entries() { 353 return new DFEnum(this); 354 } 355 356 /* 357 * Helper class. 358 */ 359 private static class DFEnum implements Enumeration<String> { 360 private int mIndex; 361 @UnsupportedAppUsage 362 private String[] mNameList; 363 DFEnum(DexFile df)364 DFEnum(DexFile df) { 365 mIndex = 0; 366 mNameList = getClassNameList(df.mCookie); 367 } 368 hasMoreElements()369 public boolean hasMoreElements() { 370 return (mIndex < mNameList.length); 371 } 372 nextElement()373 public String nextElement() { 374 return mNameList[mIndex++]; 375 } 376 } 377 378 /** 379 * Called when the class is finalized. Makes sure the DEX file is closed. 380 * 381 * @throws IOException 382 * if an I/O error occurs during closing the file, which 383 * normally should not happen 384 */ finalize()385 @Override protected void finalize() throws Throwable { 386 try { 387 if (mInternalCookie != null && !closeDexFile(mInternalCookie)) { 388 throw new AssertionError("Failed to close dex file in finalizer."); 389 } 390 mInternalCookie = null; 391 mCookie = null; 392 } finally { 393 super.finalize(); 394 } 395 } 396 397 398 /* 399 * Open a DEX file. The value returned is a magic VM cookie. On 400 * failure, an IOException is thrown. 401 */ 402 @UnsupportedAppUsage openDexFile(String sourceName, String outputName, int flags, ClassLoader loader, DexPathList.Element[] elements)403 private static Object openDexFile(String sourceName, String outputName, int flags, 404 ClassLoader loader, DexPathList.Element[] elements) throws IOException { 405 // Use absolute paths to enable the use of relative paths when testing on host. 406 return openDexFileNative(new File(sourceName).getAbsolutePath(), 407 (outputName == null) 408 ? null 409 : new File(outputName).getAbsolutePath(), 410 flags, 411 loader, 412 elements); 413 } 414 openInMemoryDexFiles(ByteBuffer[] bufs, ClassLoader loader, DexPathList.Element[] elements)415 private static Object openInMemoryDexFiles(ByteBuffer[] bufs, ClassLoader loader, 416 DexPathList.Element[] elements) throws IOException { 417 // Preprocess the ByteBuffers for openInMemoryDexFilesNative. We extract 418 // the backing array (non-direct buffers only) and start/end positions 419 // so that the native method does not have to call Java methods anymore. 420 byte[][] arrays = new byte[bufs.length][]; 421 int[] starts = new int[bufs.length]; 422 int[] ends = new int[bufs.length]; 423 for (int i = 0; i < bufs.length; ++i) { 424 arrays[i] = bufs[i].isDirect() ? null : bufs[i].array(); 425 starts[i] = bufs[i].position(); 426 ends[i] = bufs[i].limit(); 427 } 428 return openInMemoryDexFilesNative(bufs, arrays, starts, ends, loader, elements); 429 } 430 openInMemoryDexFilesNative(ByteBuffer[] bufs, byte[][] arrays, int[] starts, int[] ends, ClassLoader loader, DexPathList.Element[] elements)431 private static native Object openInMemoryDexFilesNative(ByteBuffer[] bufs, byte[][] arrays, 432 int[] starts, int[] ends, ClassLoader loader, DexPathList.Element[] elements); 433 434 /* 435 * Initiates background verification of this DexFile. This is a sepearate down-call 436 * from openDexFile and openInMemoryDexFiles because it requires the class loader's 437 * DexPathList to have been initialized for its classes to be resolvable by ART. 438 * DexPathList will open the dex files first, finalize `dexElements` and then call this. 439 */ verifyInBackground(ClassLoader classLoader)440 /*package*/ void verifyInBackground(ClassLoader classLoader) { 441 verifyInBackgroundNative(mCookie, classLoader); 442 } 443 verifyInBackgroundNative(Object mCookie, ClassLoader classLoader)444 private static native void verifyInBackgroundNative(Object mCookie, ClassLoader classLoader); 445 446 /* 447 * Returns true if the dex file is backed by a valid oat file. 448 */ 449 @UnsupportedAppUsage isBackedByOatFile()450 /*package*/ boolean isBackedByOatFile() { 451 return isBackedByOatFile(mCookie); 452 } 453 454 /* 455 * Set the dex file as trusted: it can access hidden APIs of the platform. 456 */ setTrusted()457 /*package*/ void setTrusted() { 458 setTrusted(mCookie); 459 } 460 461 /* 462 * Returns true if we managed to close the dex file. 463 */ closeDexFile(Object cookie)464 private static native boolean closeDexFile(Object cookie); defineClassNative(String name, ClassLoader loader, Object cookie, DexFile dexFile)465 private static native Class defineClassNative(String name, ClassLoader loader, Object cookie, 466 DexFile dexFile) 467 throws ClassNotFoundException, NoClassDefFoundError; 468 @UnsupportedAppUsage getClassNameList(Object cookie)469 private static native String[] getClassNameList(Object cookie); isBackedByOatFile(Object cookie)470 private static native boolean isBackedByOatFile(Object cookie); setTrusted(Object cookie)471 private static native void setTrusted(Object cookie); 472 /* 473 * Open a DEX file. The value returned is a magic VM cookie. On 474 * failure, an IOException is thrown. 475 */ 476 @UnsupportedAppUsage openDexFileNative(String sourceName, String outputName, int flags, ClassLoader loader, DexPathList.Element[] elements)477 private static native Object openDexFileNative(String sourceName, String outputName, int flags, 478 ClassLoader loader, DexPathList.Element[] elements); 479 480 /** 481 * Returns true if the VM believes that the apk/jar file is out of date 482 * and should be passed through "dexopt" again. 483 * 484 * @param fileName the absolute path to the apk/jar file to examine. 485 * @return true if dexopt should be called on the file, false otherwise. 486 * @throws java.io.FileNotFoundException if fileName is not readable, 487 * not a file, or not present. 488 * @throws java.io.IOException if fileName is not a valid apk/jar file or 489 * if problems occur while parsing it. 490 * @throws java.lang.NullPointerException if fileName is null. 491 * 492 * @deprecated Use {@code Artd.getDexoptNeeded} instead. 493 */ 494 @Deprecated isDexOptNeeded(String fileName)495 public static native boolean isDexOptNeeded(String fileName) 496 throws FileNotFoundException, IOException; 497 498 /** 499 * No dexopt should (or can) be done to update the apk/jar. 500 * 501 * See {@link #getDexOptNeeded(String, String, String, boolean, boolean)}. 502 * 503 * @hide 504 */ 505 @SystemApi(client = MODULE_LIBRARIES) 506 @Deprecated 507 public static final int NO_DEXOPT_NEEDED = 0; 508 509 /** 510 * dex2oat should be run to update the apk/jar from scratch. 511 * 512 * See {@link #getDexOptNeeded(String, String, String, boolean, boolean)}. 513 * 514 * @hide 515 */ 516 @Deprecated 517 public static final int DEX2OAT_FROM_SCRATCH = 1; 518 519 /** 520 * dex2oat should be run to update the apk/jar because the existing code 521 * is out of date with respect to the boot image. 522 * 523 * See {@link #getDexOptNeeded(String, String, String, boolean, boolean)}. 524 * 525 * @hide 526 */ 527 @Deprecated 528 public static final int DEX2OAT_FOR_BOOT_IMAGE = 2; 529 530 /** 531 * dex2oat should be run to update the apk/jar because the existing code 532 * is out of date with respect to the target compiler filter. 533 * 534 * See {@link #getDexOptNeeded(String, String, String, boolean, boolean)}. 535 * 536 * @hide 537 */ 538 @SystemApi(client = MODULE_LIBRARIES) 539 @Deprecated 540 public static final int DEX2OAT_FOR_FILTER = 3; 541 542 543 /** 544 * Calls {@link #getDexOptNeeded(String, String, String, String, String, boolean, boolean)} 545 * with a null class loader context. 546 * 547 * TODO(ngeoffray, calin): deprecate / remove. 548 * @hide 549 */ getDexOptNeeded(String fileName, String instructionSet, String compilerFilter, boolean newProfile, boolean downgrade)550 public static int getDexOptNeeded(String fileName, 551 String instructionSet, String compilerFilter, boolean newProfile, boolean downgrade) 552 throws FileNotFoundException, IOException { 553 return getDexOptNeeded( 554 fileName, instructionSet, compilerFilter, null, newProfile, downgrade); 555 } 556 557 /** 558 * Returns the VM's opinion of what kind of dexopt is needed to make the 559 * apk/jar file up to date, where {@code targetMode} is used to indicate what 560 * type of compilation the caller considers up-to-date, and {@code newProfile} 561 * is used to indicate whether profile information has changed recently. 562 * 563 * @param fileName the absolute path to the apk/jar file to examine. 564 * @param instructionSet instruction set to examine 565 * @param compilerFilter a compiler filter to use for what a caller considers up-to-date. 566 * @param classLoaderContext a string encoding the class loader context the dex file 567 * is intended to have at runtime. 568 * @param newProfile flag that describes whether a profile corresponding 569 * to the dex file has been recently updated and should be considered 570 * in the state of the file. 571 * @param downgrade flag that describes if the purpose of dexopt is to downgrade the 572 * compiler filter. If set to false, will be evaluated as an upgrade request. 573 * @return NO_DEXOPT_NEEDED, or DEX2OAT_*. See documentation 574 * of the particular status code for more information on its 575 * meaning. Returns a positive status code if the status refers to 576 * the oat file in the oat location. Returns a negative status 577 * code if the status refers to the oat file in the odex location. 578 * @throws java.io.FileNotFoundException if fileName is not readable, 579 * not a file, or not present. 580 * @throws java.io.IOException if fileName is not a valid apk/jar file or 581 * if problems occur while parsing it. 582 * @throws java.lang.NullPointerException if {@code fileName} is {@code null}. 583 * @deprecated Use {@code Artd.getDexoptNeeded} instead. 584 * 585 * @hide 586 */ 587 @SystemApi(client = MODULE_LIBRARIES) 588 @Deprecated getDexOptNeeded(@onNull String fileName, @NonNull String instructionSet, @NonNull String compilerFilter, @Nullable String classLoaderContext, boolean newProfile, boolean downgrade)589 public static native int getDexOptNeeded(@NonNull String fileName, 590 @NonNull String instructionSet, @NonNull String compilerFilter, @Nullable String classLoaderContext, 591 boolean newProfile, boolean downgrade) 592 throws FileNotFoundException, IOException; 593 594 /** 595 * Returns the status of the dex file {@code fileName}. The returned string is 596 * an opaque, human readable representation of the current status. The output 597 * is only meant for debugging and is not guaranteed to be stable across 598 * releases and/or devices. 599 * 600 * @hide 601 */ getDexFileStatus(String fileName, String instructionSet)602 public static native String getDexFileStatus(String fileName, String instructionSet) 603 throws FileNotFoundException; 604 605 /** 606 * Encapsulates information about the optimizations performed on a dex file. 607 * 608 * Note that the info is only meant for debugging and is not guaranteed to be 609 * stable across releases and/or devices. 610 */ 611 public static final class OptimizationInfo { 612 // The human readable refined optimization status of the validity of the odex file. 613 private final String status; 614 // The optimization reason. The reason might be "unknown" if the 615 // the compiler artifacts were not annotated during optimizations. 616 private final String reason; 617 OptimizationInfo(String status, String reason)618 private OptimizationInfo(String status, String reason) { 619 this.status = status; 620 this.reason = reason; 621 } 622 623 /** 624 * Returns the human readable refined status of the validity of the odex file. 625 * 626 * @return optimization status 627 * 628 * @hide 629 */ 630 @SystemApi(client = MODULE_LIBRARIES) getStatus()631 public @NonNull String getStatus() { 632 return status; 633 } 634 635 /** 636 * Returns the reason of a particular optimization used. 637 * 638 * @return optimization reason 639 * 640 * @hide 641 */ 642 @SystemApi(client = MODULE_LIBRARIES) getReason()643 public @NonNull String getReason() { 644 return reason; 645 } 646 647 /** 648 * Returns whether the dex file is verified. 649 */ isVerified()650 public boolean isVerified() { 651 return isVerifiedCompilerFilter(status); 652 } 653 654 /** 655 * Returns whether the dex file is in an optimal state. Currently, this means the dex file 656 * is either ahead-of-time compiled with a profile or fully ahead-of-time compiled. 657 */ isOptimized()658 public boolean isOptimized() { 659 return isOptimizedCompilerFilter(status); 660 } 661 662 /** 663 * Returns whether the dex file is fully ahead-of-time compiled. 664 */ isFullyCompiled()665 public boolean isFullyCompiled() { 666 return isOptimizedCompilerFilter(status) && !isProfileGuidedCompilerFilter(status); 667 } 668 } 669 670 /** 671 * Retrieves the optimization info for a dex file. 672 * 673 * @param fileName path to dex file 674 * @param instructionSet instruction set to get optimization info for 675 * @return {@link OptimizationInfo} for {@code fileName} dex file 676 * @throws FileNotFoundException if {@code fileName} not found 677 * @deprecated Applications should use {@link VMRuntime#getCurrentOptimizationStatus()}. 678 * System server should use {@code ArtManagerLocal.getOptimizationStatus}. 679 * 680 * @hide 681 */ 682 @SystemApi(client = MODULE_LIBRARIES) 683 @Deprecated getDexFileOptimizationInfo( @onNull String fileName, @NonNull String instructionSet)684 public static @NonNull OptimizationInfo getDexFileOptimizationInfo( 685 @NonNull String fileName, @NonNull String instructionSet) throws FileNotFoundException { 686 String[] status = getDexFileOptimizationStatus(fileName, instructionSet); 687 return new OptimizationInfo(status[0], status[1]); 688 } 689 690 /** 691 * Returns the optimization status of the dex file {@code fileName}. The returned 692 * array will have 2 elements which specify: 693 * - index 0: the level of optimizations 694 * - index 1: the optimization reason. The reason might be "unknown" if the 695 * the compiler artifacts were not annotated during optimizations. 696 * 697 * The output is only meant for debugging and is not guaranteed to be stable across 698 * releases and/or devices. 699 * 700 * @hide 701 */ getDexFileOptimizationStatus( String fileName, String instructionSet)702 private static native String[] getDexFileOptimizationStatus( 703 String fileName, String instructionSet) throws FileNotFoundException; 704 705 /** 706 * Returns the paths of the optimized files generated for {@code fileName}. 707 * If no optimized code exists the method returns {@code null}. 708 * 709 * @param fileName path to dex file 710 * @param instructionSet instruction set to get optimized files for 711 * @return paths to optimized code, or {@code null} if they do not exist 712 * @throws FileNotFoundException 713 * 714 * @hide 715 */ 716 @SystemApi(client = MODULE_LIBRARIES) getDexFileOutputPaths(@onNull String fileName, @NonNull String instructionSet)717 public static native @Nullable String[] getDexFileOutputPaths(@NonNull String fileName, @NonNull String instructionSet) 718 throws FileNotFoundException; 719 720 /** 721 * Returns whether the given filter is a valid filter. 722 * 723 * @param filter filter string 724 * @return whether given filter string is a valid filter 725 * 726 * @hide 727 */ 728 @SystemApi(client = MODULE_LIBRARIES) isValidCompilerFilter(@onNull String filter)729 public native static boolean isValidCompilerFilter(@NonNull String filter); 730 731 /** 732 * Returns whether the given filter is based on profiles. 733 * 734 * @param filter filter string 735 * @return whether given filter string is based on profiles 736 * 737 * @hide 738 */ 739 @SystemApi(client = MODULE_LIBRARIES) isProfileGuidedCompilerFilter(@onNull String filter)740 public native static boolean isProfileGuidedCompilerFilter(@NonNull String filter); 741 742 /** 743 * Returns whether the given filter includes verification. 744 * 745 * @hide 746 */ 747 @SystemApi(client = MODULE_LIBRARIES) isVerifiedCompilerFilter(@onNull String filter)748 public native static boolean isVerifiedCompilerFilter(@NonNull String filter); 749 750 /** 751 * Returns whether the given filter includes AOT compilation. 752 * 753 * @hide 754 */ 755 @SystemApi(client = MODULE_LIBRARIES) isOptimizedCompilerFilter(@onNull String filter)756 public native static boolean isOptimizedCompilerFilter(@NonNull String filter); 757 758 /** 759 * Returns whether JAR/DEX files' read-only status is enforced. 760 * 761 * @see #ENFORCE_READ_ONLY_JAVA_DCL 762 * @hide 763 */ 764 @TestApi isReadOnlyJavaDclEnforced()765 public static native boolean isReadOnlyJavaDclEnforced(); 766 767 /** 768 * Returns the version of the compiler filter that is not based on profiles. 769 * If the input is not a valid filter, or the filter is already not based on 770 * profiles, this returns the input. 771 * 772 * @param filter filter string 773 * @return version of the compiler filter that is not based on profiles 774 * 775 * @hide 776 */ getNonProfileGuidedCompilerFilter(String filter)777 public native static String getNonProfileGuidedCompilerFilter(String filter); 778 779 /** 780 * Returns the version of the compiler filter that is suitable for safe mode. 781 * If the input is not a valid filter, or the filter is already suitable for 782 * safe mode, this returns the input. 783 * 784 * @param filter filter string 785 * @return version of the compiler filter that is suitable for safe mode 786 * 787 * @hide 788 */ 789 @SystemApi(client = MODULE_LIBRARIES) getSafeModeCompilerFilter(@onNull String filter)790 public native static @NonNull String getSafeModeCompilerFilter(@NonNull String filter); 791 792 /** 793 * Returns the static file size of the original dex file. 794 * The original size of the uncompressed dex file is returned. 795 * On device the dex file may be compressed or embedded in some other 796 * file (e.g. oat) in a platform implementation dependent manner. This 797 * method abstracts away from those details and provides an efficient 798 * implementation given that the dex file in question has already been 799 * uncompressed, extracted, and/or loaded by the runtime as appropriate. 800 * <p> 801 * In the case of multidex, returns the sum of the original uncompressed 802 * multidex entry file sizes. 803 * 804 * @hide 805 */ getStaticSizeOfDexFile()806 public long getStaticSizeOfDexFile() { 807 return getStaticSizeOfDexFile(mCookie); 808 } 809 getStaticSizeOfDexFile(Object cookie)810 private static native long getStaticSizeOfDexFile(Object cookie); 811 } 812