812 lines
30 KiB
Java
812 lines
30 KiB
Java
![]() |
/*
|
||
|
* Copyright (C) 2007 The Android Open Source Project
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
package dalvik.system;
|
||
|
|
||
|
import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
|
||
|
|
||
|
import android.annotation.SystemApi;
|
||
|
import android.annotation.TestApi;
|
||
|
import android.compat.annotation.ChangeId;
|
||
|
import android.compat.annotation.EnabledAfter;
|
||
|
import android.compat.annotation.UnsupportedAppUsage;
|
||
|
import android.system.ErrnoException;
|
||
|
|
||
|
import dalvik.annotation.compat.VersionCodes;
|
||
|
import dalvik.annotation.optimization.ReachabilitySensitive;
|
||
|
|
||
|
import libcore.io.Libcore;
|
||
|
import libcore.util.NonNull;
|
||
|
import libcore.util.Nullable;
|
||
|
|
||
|
import java.io.File;
|
||
|
import java.io.FileNotFoundException;
|
||
|
import java.io.IOException;
|
||
|
import java.nio.ByteBuffer;
|
||
|
import java.util.Arrays;
|
||
|
import java.util.Enumeration;
|
||
|
import java.util.List;
|
||
|
|
||
|
/**
|
||
|
* Loads DEX files. This class is meant for internal use and should not be used by applications.
|
||
|
*
|
||
|
* Applications should not instantiate this class. It will hurt performance in most cases and will
|
||
|
* lead to incorrect execution of bytecode in the worst case. Applications should use one of the
|
||
|
* standard classloaders such as {@link dalvik.system.PathClassLoader} instead. <b>Non-static APIs
|
||
|
* will be removed in a future Android release</b>.
|
||
|
*/
|
||
|
public final class DexFile {
|
||
|
/**
|
||
|
* If close is called, mCookie becomes null but the internal cookie is preserved if the close
|
||
|
* failed so that we can free resources in the finalizer.
|
||
|
*/
|
||
|
@UnsupportedAppUsage
|
||
|
@ReachabilitySensitive
|
||
|
private Object mCookie;
|
||
|
|
||
|
@UnsupportedAppUsage
|
||
|
private Object mInternalCookie;
|
||
|
@UnsupportedAppUsage
|
||
|
private final String mFileName;
|
||
|
|
||
|
/**
|
||
|
* Enforce the file passed to open DexFile to be set as read-only for apps targeting U+. This
|
||
|
* is to prevent files to be dynamically loaded being unexpectedly overwritten by
|
||
|
* malicious actors.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
// TODO (topjohnwu@): change to @EnabledSince with U API version
|
||
|
@TestApi
|
||
|
@ChangeId
|
||
|
@EnabledAfter(targetSdkVersion = VersionCodes.TIRAMISU)
|
||
|
public static final long ENFORCE_READ_ONLY_JAVA_DCL = 218865702;
|
||
|
|
||
|
/**
|
||
|
* Opens a DEX file from a given File object.
|
||
|
*
|
||
|
* @deprecated Applications should use one of the standard classloaders such
|
||
|
* as {@link dalvik.system.PathClassLoader} instead. <b>This API will be removed
|
||
|
* in a future Android release</b>.
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public DexFile(File file) throws IOException {
|
||
|
this(file.getPath());
|
||
|
}
|
||
|
/*
|
||
|
* Private version with class loader argument.
|
||
|
*
|
||
|
* @param file
|
||
|
* the File object referencing the actual DEX file
|
||
|
* @param loader
|
||
|
* the class loader object creating the DEX file object
|
||
|
* @param elements
|
||
|
* the temporary dex path list elements from DexPathList.makeElements
|
||
|
*/
|
||
|
DexFile(File file, ClassLoader loader, DexPathList.Element[] elements)
|
||
|
throws IOException {
|
||
|
this(file.getPath(), loader, elements);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Opens a DEX file from a given filename.
|
||
|
*
|
||
|
* @deprecated Applications should use one of the standard classloaders such
|
||
|
* as {@link dalvik.system.PathClassLoader} instead. <b>This API will be removed
|
||
|
* in a future Android release</b>.
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public DexFile(String fileName) throws IOException {
|
||
|
this(fileName, null, null);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Private version with class loader argument.
|
||
|
*
|
||
|
* @param fileName
|
||
|
* the filename of the DEX file
|
||
|
* @param loader
|
||
|
* the class loader creating the DEX file object
|
||
|
* @param elements
|
||
|
* the temporary dex path list elements from DexPathList.makeElements
|
||
|
*/
|
||
|
DexFile(String fileName, ClassLoader loader, DexPathList.Element[] elements)
|
||
|
throws IOException {
|
||
|
mCookie = openDexFile(fileName, null, 0, loader, elements);
|
||
|
mInternalCookie = mCookie;
|
||
|
mFileName = fileName;
|
||
|
//System.out.println("DEX FILE cookie is " + mCookie + " fileName=" + fileName);
|
||
|
}
|
||
|
|
||
|
DexFile(ByteBuffer[] bufs, ClassLoader loader, DexPathList.Element[] elements)
|
||
|
throws IOException {
|
||
|
mCookie = openInMemoryDexFiles(bufs, loader, elements);
|
||
|
mInternalCookie = mCookie;
|
||
|
mFileName = null;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Opens a DEX file from a given filename, using a specified file
|
||
|
* to hold the optimized data.
|
||
|
*
|
||
|
* @param sourceName
|
||
|
* Jar or APK file with "classes.dex".
|
||
|
* @param outputName
|
||
|
* File that will hold the optimized form of the DEX data.
|
||
|
* @param flags
|
||
|
* Enable optional features.
|
||
|
* @param loader
|
||
|
* The class loader creating the DEX file object.
|
||
|
* @param elements
|
||
|
* The temporary dex path list elements from DexPathList.makeElements
|
||
|
*/
|
||
|
private DexFile(String sourceName, String outputName, int flags, ClassLoader loader,
|
||
|
DexPathList.Element[] elements) throws IOException {
|
||
|
if (outputName != null) {
|
||
|
try {
|
||
|
String parent = new File(outputName).getParent();
|
||
|
if (Libcore.os.getuid() != Libcore.os.stat(parent).st_uid) {
|
||
|
throw new IllegalArgumentException("Optimized data directory " + parent
|
||
|
+ " is not owned by the current user. Shared storage cannot protect"
|
||
|
+ " your application from code injection attacks.");
|
||
|
}
|
||
|
} catch (ErrnoException ignored) {
|
||
|
// assume we'll fail with a more contextual error later
|
||
|
}
|
||
|
}
|
||
|
|
||
|
mCookie = openDexFile(sourceName, outputName, flags, loader, elements);
|
||
|
mInternalCookie = mCookie;
|
||
|
mFileName = sourceName;
|
||
|
//System.out.println("DEX FILE cookie is " + mCookie + " sourceName=" + sourceName + " outputName=" + outputName);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Open a DEX file, specifying the file in which the optimized DEX
|
||
|
* data should be written. If the optimized form exists and appears
|
||
|
* to be current, it will be used; if not, the VM will attempt to
|
||
|
* regenerate it.
|
||
|
*
|
||
|
* @deprecated Applications should use one of the standard classloaders such
|
||
|
* as {@link dalvik.system.PathClassLoader} instead. <b>This API will be removed
|
||
|
* in a future Android release</b>.
|
||
|
*/
|
||
|
@Deprecated
|
||
|
static public DexFile loadDex(String sourcePathName, String outputPathName,
|
||
|
int flags) throws IOException {
|
||
|
|
||
|
/*
|
||
|
* TODO: we may want to cache previously-opened DexFile objects.
|
||
|
* The cache would be synchronized with close(). This would help
|
||
|
* us avoid mapping the same DEX more than once when an app
|
||
|
* decided to open it multiple times. In practice this may not
|
||
|
* be a real issue.
|
||
|
*/
|
||
|
return loadDex(sourcePathName, outputPathName, flags, null, null);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Private version of loadDex that also takes a class loader.
|
||
|
*
|
||
|
* @param sourcePathName
|
||
|
* Jar or APK file with "classes.dex". (May expand this to include
|
||
|
* "raw DEX" in the future.)
|
||
|
* @param outputPathName
|
||
|
* File that will hold the optimized form of the DEX data.
|
||
|
* @param flags
|
||
|
* Enable optional features. (Currently none defined.)
|
||
|
* @param loader
|
||
|
* Class loader that is aloading the DEX file.
|
||
|
* @param elements
|
||
|
* The temporary dex path list elements from DexPathList.makeElements
|
||
|
* @return
|
||
|
* A new or previously-opened DexFile.
|
||
|
* @throws IOException
|
||
|
* If unable to open the source or output file.
|
||
|
*/
|
||
|
@UnsupportedAppUsage
|
||
|
static DexFile loadDex(String sourcePathName, String outputPathName,
|
||
|
int flags, ClassLoader loader, DexPathList.Element[] elements) throws IOException {
|
||
|
|
||
|
/*
|
||
|
* TODO: we may want to cache previously-opened DexFile objects.
|
||
|
* The cache would be synchronized with close(). This would help
|
||
|
* us avoid mapping the same DEX more than once when an app
|
||
|
* decided to open it multiple times. In practice this may not
|
||
|
* be a real issue.
|
||
|
*/
|
||
|
return new DexFile(sourcePathName, outputPathName, flags, loader, elements);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Gets the name of the (already opened) DEX file.
|
||
|
*
|
||
|
* @return the file name
|
||
|
*
|
||
|
* @deprecated Applications should use one of the standard classloaders such
|
||
|
* as {@link dalvik.system.PathClassLoader} instead. <b>This API will be removed
|
||
|
* in a future Android release</b>.
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public String getName() {
|
||
|
return mFileName;
|
||
|
}
|
||
|
|
||
|
@Override public String toString() {
|
||
|
if (mFileName != null) {
|
||
|
return getName();
|
||
|
} else {
|
||
|
return "InMemoryDexFile[cookie=" + Arrays.toString((long[]) mCookie) + "]";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Closes the DEX file.
|
||
|
* <p>
|
||
|
* This may not be able to release all of the resources. If classes from this DEX file are
|
||
|
* still resident, the DEX file can't be unmapped. In the case where we do not release all
|
||
|
* the resources, close is called again in the finalizer.
|
||
|
*
|
||
|
* @throws IOException
|
||
|
* if an I/O error occurs during closing the file, which
|
||
|
* normally should not happen
|
||
|
*
|
||
|
* @deprecated Applications should use one of the standard classloaders such
|
||
|
* as {@link dalvik.system.PathClassLoader} instead. <b>This API will be removed
|
||
|
* in a future Android release</b>.
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public void close() throws IOException {
|
||
|
if (mInternalCookie != null) {
|
||
|
if (closeDexFile(mInternalCookie)) {
|
||
|
mInternalCookie = null;
|
||
|
}
|
||
|
mCookie = null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Loads a class. Returns the class on success, or a {@code null} reference
|
||
|
* on failure.
|
||
|
* <p>
|
||
|
* If you are not calling this from a class loader, this is most likely not
|
||
|
* going to do what you want. Use {@link Class#forName(String)} instead.
|
||
|
* <p>
|
||
|
* The method does not throw {@link ClassNotFoundException} if the class
|
||
|
* isn't found because it isn't reasonable to throw exceptions wildly every
|
||
|
* time a class is not found in the first DEX file we look at.
|
||
|
*
|
||
|
* @param name
|
||
|
* the class name, which should look like "java/lang/String"
|
||
|
*
|
||
|
* @param loader
|
||
|
* the class loader that tries to load the class (in most cases
|
||
|
* the caller of the method
|
||
|
*
|
||
|
* @return the {@link Class} object representing the class, or {@code null}
|
||
|
* if the class cannot be loaded
|
||
|
*
|
||
|
* @deprecated Applications should use one of the standard classloaders such
|
||
|
* as {@link dalvik.system.PathClassLoader} instead. <b>This API will be removed
|
||
|
* in a future Android release</b>.
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public Class loadClass(String name, ClassLoader loader) {
|
||
|
String slashName = name.replace('.', '/');
|
||
|
return loadClassBinaryName(slashName, loader, null);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* See {@link #loadClass(String, ClassLoader)}.
|
||
|
*
|
||
|
* This takes a "binary" class name to better match ClassLoader semantics.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
@UnsupportedAppUsage
|
||
|
public Class loadClassBinaryName(String name, ClassLoader loader, List<Throwable> suppressed) {
|
||
|
return defineClass(name, loader, mCookie, this, suppressed);
|
||
|
}
|
||
|
|
||
|
private static Class defineClass(String name, ClassLoader loader, Object cookie,
|
||
|
DexFile dexFile, List<Throwable> suppressed) {
|
||
|
Class result = null;
|
||
|
try {
|
||
|
result = defineClassNative(name, loader, cookie, dexFile);
|
||
|
} catch (NoClassDefFoundError e) {
|
||
|
if (suppressed != null) {
|
||
|
suppressed.add(e);
|
||
|
}
|
||
|
} catch (ClassNotFoundException e) {
|
||
|
if (suppressed != null) {
|
||
|
suppressed.add(e);
|
||
|
}
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Enumerate the names of the classes in this DEX file.
|
||
|
*
|
||
|
* @return an enumeration of names of classes contained in the DEX file, in
|
||
|
* the usual internal form (like "java/lang/String").
|
||
|
*
|
||
|
* @deprecated Applications should use one of the standard classloaders such
|
||
|
* as {@link dalvik.system.PathClassLoader} instead. <b>This API will be removed
|
||
|
* in a future Android release</b>.
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public Enumeration<String> entries() {
|
||
|
return new DFEnum(this);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Helper class.
|
||
|
*/
|
||
|
private static class DFEnum implements Enumeration<String> {
|
||
|
private int mIndex;
|
||
|
@UnsupportedAppUsage
|
||
|
private String[] mNameList;
|
||
|
|
||
|
DFEnum(DexFile df) {
|
||
|
mIndex = 0;
|
||
|
mNameList = getClassNameList(df.mCookie);
|
||
|
}
|
||
|
|
||
|
public boolean hasMoreElements() {
|
||
|
return (mIndex < mNameList.length);
|
||
|
}
|
||
|
|
||
|
public String nextElement() {
|
||
|
return mNameList[mIndex++];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Called when the class is finalized. Makes sure the DEX file is closed.
|
||
|
*
|
||
|
* @throws IOException
|
||
|
* if an I/O error occurs during closing the file, which
|
||
|
* normally should not happen
|
||
|
*/
|
||
|
@Override protected void finalize() throws Throwable {
|
||
|
try {
|
||
|
if (mInternalCookie != null && !closeDexFile(mInternalCookie)) {
|
||
|
throw new AssertionError("Failed to close dex file in finalizer.");
|
||
|
}
|
||
|
mInternalCookie = null;
|
||
|
mCookie = null;
|
||
|
} finally {
|
||
|
super.finalize();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Open a DEX file. The value returned is a magic VM cookie. On
|
||
|
* failure, an IOException is thrown.
|
||
|
*/
|
||
|
@UnsupportedAppUsage
|
||
|
private static Object openDexFile(String sourceName, String outputName, int flags,
|
||
|
ClassLoader loader, DexPathList.Element[] elements) throws IOException {
|
||
|
// Use absolute paths to enable the use of relative paths when testing on host.
|
||
|
return openDexFileNative(new File(sourceName).getAbsolutePath(),
|
||
|
(outputName == null)
|
||
|
? null
|
||
|
: new File(outputName).getAbsolutePath(),
|
||
|
flags,
|
||
|
loader,
|
||
|
elements);
|
||
|
}
|
||
|
|
||
|
private static Object openInMemoryDexFiles(ByteBuffer[] bufs, ClassLoader loader,
|
||
|
DexPathList.Element[] elements) throws IOException {
|
||
|
// Preprocess the ByteBuffers for openInMemoryDexFilesNative. We extract
|
||
|
// the backing array (non-direct buffers only) and start/end positions
|
||
|
// so that the native method does not have to call Java methods anymore.
|
||
|
byte[][] arrays = new byte[bufs.length][];
|
||
|
int[] starts = new int[bufs.length];
|
||
|
int[] ends = new int[bufs.length];
|
||
|
for (int i = 0; i < bufs.length; ++i) {
|
||
|
arrays[i] = bufs[i].isDirect() ? null : bufs[i].array();
|
||
|
starts[i] = bufs[i].position();
|
||
|
ends[i] = bufs[i].limit();
|
||
|
}
|
||
|
return openInMemoryDexFilesNative(bufs, arrays, starts, ends, loader, elements);
|
||
|
}
|
||
|
|
||
|
private static native Object openInMemoryDexFilesNative(ByteBuffer[] bufs, byte[][] arrays,
|
||
|
int[] starts, int[] ends, ClassLoader loader, DexPathList.Element[] elements);
|
||
|
|
||
|
/*
|
||
|
* Initiates background verification of this DexFile. This is a sepearate down-call
|
||
|
* from openDexFile and openInMemoryDexFiles because it requires the class loader's
|
||
|
* DexPathList to have been initialized for its classes to be resolvable by ART.
|
||
|
* DexPathList will open the dex files first, finalize `dexElements` and then call this.
|
||
|
*/
|
||
|
/*package*/ void verifyInBackground(ClassLoader classLoader) {
|
||
|
verifyInBackgroundNative(mCookie, classLoader);
|
||
|
}
|
||
|
|
||
|
private static native void verifyInBackgroundNative(Object mCookie, ClassLoader classLoader);
|
||
|
|
||
|
/*
|
||
|
* Returns true if the dex file is backed by a valid oat file.
|
||
|
*/
|
||
|
@UnsupportedAppUsage
|
||
|
/*package*/ boolean isBackedByOatFile() {
|
||
|
return isBackedByOatFile(mCookie);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Set the dex file as trusted: it can access hidden APIs of the platform.
|
||
|
*/
|
||
|
/*package*/ void setTrusted() {
|
||
|
setTrusted(mCookie);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Returns true if we managed to close the dex file.
|
||
|
*/
|
||
|
private static native boolean closeDexFile(Object cookie);
|
||
|
private static native Class defineClassNative(String name, ClassLoader loader, Object cookie,
|
||
|
DexFile dexFile)
|
||
|
throws ClassNotFoundException, NoClassDefFoundError;
|
||
|
@UnsupportedAppUsage
|
||
|
private static native String[] getClassNameList(Object cookie);
|
||
|
private static native boolean isBackedByOatFile(Object cookie);
|
||
|
private static native void setTrusted(Object cookie);
|
||
|
/*
|
||
|
* Open a DEX file. The value returned is a magic VM cookie. On
|
||
|
* failure, an IOException is thrown.
|
||
|
*/
|
||
|
@UnsupportedAppUsage
|
||
|
private static native Object openDexFileNative(String sourceName, String outputName, int flags,
|
||
|
ClassLoader loader, DexPathList.Element[] elements);
|
||
|
|
||
|
/**
|
||
|
* Returns true if the VM believes that the apk/jar file is out of date
|
||
|
* and should be passed through "dexopt" again.
|
||
|
*
|
||
|
* @param fileName the absolute path to the apk/jar file to examine.
|
||
|
* @return true if dexopt should be called on the file, false otherwise.
|
||
|
* @throws java.io.FileNotFoundException if fileName is not readable,
|
||
|
* not a file, or not present.
|
||
|
* @throws java.io.IOException if fileName is not a valid apk/jar file or
|
||
|
* if problems occur while parsing it.
|
||
|
* @throws java.lang.NullPointerException if fileName is null.
|
||
|
*
|
||
|
* @deprecated Use {@code Artd.getDexoptNeeded} instead.
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public static native boolean isDexOptNeeded(String fileName)
|
||
|
throws FileNotFoundException, IOException;
|
||
|
|
||
|
/**
|
||
|
* No dexopt should (or can) be done to update the apk/jar.
|
||
|
*
|
||
|
* See {@link #getDexOptNeeded(String, String, String, boolean, boolean)}.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
@SystemApi(client = MODULE_LIBRARIES)
|
||
|
@Deprecated
|
||
|
public static final int NO_DEXOPT_NEEDED = 0;
|
||
|
|
||
|
/**
|
||
|
* dex2oat should be run to update the apk/jar from scratch.
|
||
|
*
|
||
|
* See {@link #getDexOptNeeded(String, String, String, boolean, boolean)}.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public static final int DEX2OAT_FROM_SCRATCH = 1;
|
||
|
|
||
|
/**
|
||
|
* dex2oat should be run to update the apk/jar because the existing code
|
||
|
* is out of date with respect to the boot image.
|
||
|
*
|
||
|
* See {@link #getDexOptNeeded(String, String, String, boolean, boolean)}.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
@Deprecated
|
||
|
public static final int DEX2OAT_FOR_BOOT_IMAGE = 2;
|
||
|
|
||
|
/**
|
||
|
* dex2oat should be run to update the apk/jar because the existing code
|
||
|
* is out of date with respect to the target compiler filter.
|
||
|
*
|
||
|
* See {@link #getDexOptNeeded(String, String, String, boolean, boolean)}.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
@SystemApi(client = MODULE_LIBRARIES)
|
||
|
@Deprecated
|
||
|
public static final int DEX2OAT_FOR_FILTER = 3;
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Calls {@link #getDexOptNeeded(String, String, String, String, String, boolean, boolean)}
|
||
|
* with a null class loader context.
|
||
|
*
|
||
|
* TODO(ngeoffray, calin): deprecate / remove.
|
||
|
* @hide
|
||
|
*/
|
||
|
public static int getDexOptNeeded(String fileName,
|
||
|
String instructionSet, String compilerFilter, boolean newProfile, boolean downgrade)
|
||
|
throws FileNotFoundException, IOException {
|
||
|
return getDexOptNeeded(
|
||
|
fileName, instructionSet, compilerFilter, null, newProfile, downgrade);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the VM's opinion of what kind of dexopt is needed to make the
|
||
|
* apk/jar file up to date, where {@code targetMode} is used to indicate what
|
||
|
* type of compilation the caller considers up-to-date, and {@code newProfile}
|
||
|
* is used to indicate whether profile information has changed recently.
|
||
|
*
|
||
|
* @param fileName the absolute path to the apk/jar file to examine.
|
||
|
* @param instructionSet instruction set to examine
|
||
|
* @param compilerFilter a compiler filter to use for what a caller considers up-to-date.
|
||
|
* @param classLoaderContext a string encoding the class loader context the dex file
|
||
|
* is intended to have at runtime.
|
||
|
* @param newProfile flag that describes whether a profile corresponding
|
||
|
* to the dex file has been recently updated and should be considered
|
||
|
* in the state of the file.
|
||
|
* @param downgrade flag that describes if the purpose of dexopt is to downgrade the
|
||
|
* compiler filter. If set to false, will be evaluated as an upgrade request.
|
||
|
* @return NO_DEXOPT_NEEDED, or DEX2OAT_*. See documentation
|
||
|
* of the particular status code for more information on its
|
||
|
* meaning. Returns a positive status code if the status refers to
|
||
|
* the oat file in the oat location. Returns a negative status
|
||
|
* code if the status refers to the oat file in the odex location.
|
||
|
* @throws java.io.FileNotFoundException if fileName is not readable,
|
||
|
* not a file, or not present.
|
||
|
* @throws java.io.IOException if fileName is not a valid apk/jar file or
|
||
|
* if problems occur while parsing it.
|
||
|
* @throws java.lang.NullPointerException if {@code fileName} is {@code null}.
|
||
|
* @deprecated Use {@code Artd.getDexoptNeeded} instead.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
@SystemApi(client = MODULE_LIBRARIES)
|
||
|
@Deprecated
|
||
|
public static native int getDexOptNeeded(@NonNull String fileName,
|
||
|
@NonNull String instructionSet, @NonNull String compilerFilter, @Nullable String classLoaderContext,
|
||
|
boolean newProfile, boolean downgrade)
|
||
|
throws FileNotFoundException, IOException;
|
||
|
|
||
|
/**
|
||
|
* Returns the status of the dex file {@code fileName}. The returned string is
|
||
|
* an opaque, human readable representation of the current status. The output
|
||
|
* is only meant for debugging and is not guaranteed to be stable across
|
||
|
* releases and/or devices.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
public static native String getDexFileStatus(String fileName, String instructionSet)
|
||
|
throws FileNotFoundException;
|
||
|
|
||
|
/**
|
||
|
* Encapsulates information about the optimizations performed on a dex file.
|
||
|
*
|
||
|
* Note that the info is only meant for debugging and is not guaranteed to be
|
||
|
* stable across releases and/or devices.
|
||
|
*/
|
||
|
public static final class OptimizationInfo {
|
||
|
// The human readable refined optimization status of the validity of the odex file.
|
||
|
private final String status;
|
||
|
// The optimization reason. The reason might be "unknown" if the
|
||
|
// the compiler artifacts were not annotated during optimizations.
|
||
|
private final String reason;
|
||
|
|
||
|
private OptimizationInfo(String status, String reason) {
|
||
|
this.status = status;
|
||
|
this.reason = reason;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the human readable refined status of the validity of the odex file.
|
||
|
*
|
||
|
* @return optimization status
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
@SystemApi(client = MODULE_LIBRARIES)
|
||
|
public @NonNull String getStatus() {
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the reason of a particular optimization used.
|
||
|
*
|
||
|
* @return optimization reason
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
@SystemApi(client = MODULE_LIBRARIES)
|
||
|
public @NonNull String getReason() {
|
||
|
return reason;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns whether the dex file is verified.
|
||
|
*/
|
||
|
public boolean isVerified() {
|
||
|
return isVerifiedCompilerFilter(status);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns whether the dex file is in an optimal state. Currently, this means the dex file
|
||
|
* is either ahead-of-time compiled with a profile or fully ahead-of-time compiled.
|
||
|
*/
|
||
|
public boolean isOptimized() {
|
||
|
return isOptimizedCompilerFilter(status);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns whether the dex file is fully ahead-of-time compiled.
|
||
|
*/
|
||
|
public boolean isFullyCompiled() {
|
||
|
return isOptimizedCompilerFilter(status) && !isProfileGuidedCompilerFilter(status);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Retrieves the optimization info for a dex file.
|
||
|
*
|
||
|
* @param fileName path to dex file
|
||
|
* @param instructionSet instruction set to get optimization info for
|
||
|
* @return {@link OptimizationInfo} for {@code fileName} dex file
|
||
|
* @throws FileNotFoundException if {@code fileName} not found
|
||
|
* @deprecated Applications should use {@link VMRuntime#getCurrentOptimizationStatus()}.
|
||
|
* System server should use {@code ArtManagerLocal.getOptimizationStatus}.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
@SystemApi(client = MODULE_LIBRARIES)
|
||
|
@Deprecated
|
||
|
public static @NonNull OptimizationInfo getDexFileOptimizationInfo(
|
||
|
@NonNull String fileName, @NonNull String instructionSet) throws FileNotFoundException {
|
||
|
String[] status = getDexFileOptimizationStatus(fileName, instructionSet);
|
||
|
return new OptimizationInfo(status[0], status[1]);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the optimization status of the dex file {@code fileName}. The returned
|
||
|
* array will have 2 elements which specify:
|
||
|
* - index 0: the level of optimizations
|
||
|
* - index 1: the optimization reason. The reason might be "unknown" if the
|
||
|
* the compiler artifacts were not annotated during optimizations.
|
||
|
*
|
||
|
* The output is only meant for debugging and is not guaranteed to be stable across
|
||
|
* releases and/or devices.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
private static native String[] getDexFileOptimizationStatus(
|
||
|
String fileName, String instructionSet) throws FileNotFoundException;
|
||
|
|
||
|
/**
|
||
|
* Returns the paths of the optimized files generated for {@code fileName}.
|
||
|
* If no optimized code exists the method returns {@code null}.
|
||
|
*
|
||
|
* @param fileName path to dex file
|
||
|
* @param instructionSet instruction set to get optimized files for
|
||
|
* @return paths to optimized code, or {@code null} if they do not exist
|
||
|
* @throws FileNotFoundException
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
@SystemApi(client = MODULE_LIBRARIES)
|
||
|
public static native @Nullable String[] getDexFileOutputPaths(@NonNull String fileName, @NonNull String instructionSet)
|
||
|
throws FileNotFoundException;
|
||
|
|
||
|
/**
|
||
|
* Returns whether the given filter is a valid filter.
|
||
|
*
|
||
|
* @param filter filter string
|
||
|
* @return whether given filter string is a valid filter
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
@SystemApi(client = MODULE_LIBRARIES)
|
||
|
public native static boolean isValidCompilerFilter(@NonNull String filter);
|
||
|
|
||
|
/**
|
||
|
* Returns whether the given filter is based on profiles.
|
||
|
*
|
||
|
* @param filter filter string
|
||
|
* @return whether given filter string is based on profiles
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
@SystemApi(client = MODULE_LIBRARIES)
|
||
|
public native static boolean isProfileGuidedCompilerFilter(@NonNull String filter);
|
||
|
|
||
|
/**
|
||
|
* Returns whether the given filter includes verification.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
@SystemApi(client = MODULE_LIBRARIES)
|
||
|
public native static boolean isVerifiedCompilerFilter(@NonNull String filter);
|
||
|
|
||
|
/**
|
||
|
* Returns whether the given filter includes AOT compilation.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
@SystemApi(client = MODULE_LIBRARIES)
|
||
|
public native static boolean isOptimizedCompilerFilter(@NonNull String filter);
|
||
|
|
||
|
/**
|
||
|
* Returns whether JAR/DEX files' read-only status is enforced.
|
||
|
*
|
||
|
* @see #ENFORCE_READ_ONLY_JAVA_DCL
|
||
|
* @hide
|
||
|
*/
|
||
|
@TestApi
|
||
|
public static native boolean isReadOnlyJavaDclEnforced();
|
||
|
|
||
|
/**
|
||
|
* Returns the version of the compiler filter that is not based on profiles.
|
||
|
* If the input is not a valid filter, or the filter is already not based on
|
||
|
* profiles, this returns the input.
|
||
|
*
|
||
|
* @param filter filter string
|
||
|
* @return version of the compiler filter that is not based on profiles
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
public native static String getNonProfileGuidedCompilerFilter(String filter);
|
||
|
|
||
|
/**
|
||
|
* Returns the version of the compiler filter that is suitable for safe mode.
|
||
|
* If the input is not a valid filter, or the filter is already suitable for
|
||
|
* safe mode, this returns the input.
|
||
|
*
|
||
|
* @param filter filter string
|
||
|
* @return version of the compiler filter that is suitable for safe mode
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
@SystemApi(client = MODULE_LIBRARIES)
|
||
|
public native static @NonNull String getSafeModeCompilerFilter(@NonNull String filter);
|
||
|
|
||
|
/**
|
||
|
* Returns the static file size of the original dex file.
|
||
|
* The original size of the uncompressed dex file is returned.
|
||
|
* On device the dex file may be compressed or embedded in some other
|
||
|
* file (e.g. oat) in a platform implementation dependent manner. This
|
||
|
* method abstracts away from those details and provides an efficient
|
||
|
* implementation given that the dex file in question has already been
|
||
|
* uncompressed, extracted, and/or loaded by the runtime as appropriate.
|
||
|
* <p>
|
||
|
* In the case of multidex, returns the sum of the original uncompressed
|
||
|
* multidex entry file sizes.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
public long getStaticSizeOfDexFile() {
|
||
|
return getStaticSizeOfDexFile(mCookie);
|
||
|
}
|
||
|
|
||
|
private static native long getStaticSizeOfDexFile(Object cookie);
|
||
|
}
|