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