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