Pass class loader down to openDexFiles if possible
App image needs the class loader when it gets loaded.
Bug: 22858531
Change-Id: I315919d91822db0c73cf16b21d660d5870d5746f
diff --git a/dalvik/src/main/java/dalvik/system/DexFile.java b/dalvik/src/main/java/dalvik/system/DexFile.java
index d176b30..5620851 100644
--- a/dalvik/src/main/java/dalvik/system/DexFile.java
+++ b/dalvik/src/main/java/dalvik/system/DexFile.java
@@ -63,6 +63,17 @@
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
+ */
+ DexFile(File file, ClassLoader loader) throws IOException {
+ this(file.getPath(), loader);
+ }
/**
* Opens a DEX file from a given filename. This will usually be a ZIP/JAR
@@ -82,7 +93,19 @@
* access rights missing for opening it
*/
public DexFile(String fileName) throws IOException {
- mCookie = openDexFile(fileName, null, 0);
+ this(fileName, 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
+ */
+ DexFile(String fileName, ClassLoader loader) throws IOException {
+ mCookie = openDexFile(fileName, null, 0, loader);
mInternalCookie = mCookie;
mFileName = fileName;
guard.open("close");
@@ -99,8 +122,11 @@
* 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.
*/
- private DexFile(String sourceName, String outputName, int flags) throws IOException {
+ private DexFile(String sourceName, String outputName, int flags, ClassLoader loader)
+ throws IOException {
if (outputName != null) {
try {
String parent = new File(outputName).getParent();
@@ -114,7 +140,7 @@
}
}
- mCookie = openDexFile(sourceName, outputName, flags);
+ mCookie = openDexFile(sourceName, outputName, flags, loader);
mFileName = sourceName;
//System.out.println("DEX FILE cookie is " + mCookie + " sourceName=" + sourceName + " outputName=" + outputName);
}
@@ -153,7 +179,37 @@
* decided to open it multiple times. In practice this may not
* be a real issue.
*/
- return new DexFile(sourcePathName, outputPathName, flags);
+ return loadDex(sourcePathName, outputPathName, flags, 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.
+ * @return
+ * A new or previously-opened DexFile.
+ * @throws IOException
+ * If unable to open the source or output file.
+ */
+ static DexFile loadDex(String sourcePathName, String outputPathName,
+ int flags, ClassLoader loader) 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);
}
/**
@@ -302,11 +358,15 @@
* Open a DEX file. The value returned is a magic VM cookie. On
* failure, an IOException is thrown.
*/
- private static Object openDexFile(String sourceName, String outputName, int flags) throws IOException {
+ private static Object openDexFile(String sourceName, String outputName, int flags,
+ ClassLoader loader) 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);
+ (outputName == null)
+ ? null
+ : new File(outputName).getAbsolutePath(),
+ flags,
+ loader);
}
/*
@@ -321,7 +381,8 @@
* Open a DEX file. The value returned is a magic VM cookie. On
* failure, an IOException is thrown.
*/
- private static native Object openDexFileNative(String sourceName, String outputName, int flags);
+ private static native Object openDexFileNative(String sourceName, String outputName, int flags,
+ ClassLoader loader);
/**
* Returns true if the VM believes that the apk/jar file is out of date
diff --git a/dalvik/src/main/java/dalvik/system/DexPathList.java b/dalvik/src/main/java/dalvik/system/DexPathList.java
index 5552b1c..49da901 100644
--- a/dalvik/src/main/java/dalvik/system/DexPathList.java
+++ b/dalvik/src/main/java/dalvik/system/DexPathList.java
@@ -119,7 +119,7 @@
ArrayList<IOException> suppressedExceptions = new ArrayList<IOException>();
// save dexPath for BaseDexClassLoader
this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,
- suppressedExceptions);
+ suppressedExceptions, definingContext);
// Native libraries may exist in both the system and
// application library paths, and we use this search order:
@@ -138,7 +138,8 @@
allNativeLibraryDirectories.addAll(systemNativeLibraryDirectories);
this.nativeLibraryPathElements = makePathElements(allNativeLibraryDirectories,
- suppressedExceptions);
+ suppressedExceptions,
+ definingContext);
if (suppressedExceptions.size() > 0) {
this.dexElementsSuppressedExceptions =
@@ -212,16 +213,18 @@
* the given array.
*/
private static Element[] makeDexElements(List<File> files, File optimizedDirectory,
- List<IOException> suppressedExceptions) {
- return makeElements(files, optimizedDirectory, suppressedExceptions, false);
+ List<IOException> suppressedExceptions,
+ ClassLoader loader) {
+ return makeElements(files, optimizedDirectory, suppressedExceptions, false, loader);
}
/**
* Makes an array of directory/zip path elements, one per element of the given array.
*/
private static Element[] makePathElements(List<File> files,
- List<IOException> suppressedExceptions) {
- return makeElements(files, null, suppressedExceptions, true);
+ List<IOException> suppressedExceptions,
+ ClassLoader loader) {
+ return makeElements(files, null, suppressedExceptions, true, loader);
}
/*
@@ -230,12 +233,13 @@
*/
private static Element[] makePathElements(List<File> files, File optimizedDirectory,
List<IOException> suppressedExceptions) {
- return makeElements(files, null, suppressedExceptions, true);
+ return makeElements(files, null, suppressedExceptions, true, null);
}
private static Element[] makeElements(List<File> files, File optimizedDirectory,
List<IOException> suppressedExceptions,
- boolean ignoreDexFiles) {
+ boolean ignoreDexFiles,
+ ClassLoader loader) {
List<Element> elements = new ArrayList<>();
/*
* Open all files and load the (direct or contained) dex files
@@ -260,7 +264,7 @@
if (!ignoreDexFiles && name.endsWith(DEX_SUFFIX)) {
// Raw dex file (not inside a zip/jar).
try {
- dex = loadDexFile(file, optimizedDirectory);
+ dex = loadDexFile(file, optimizedDirectory, loader);
} catch (IOException ex) {
System.logE("Unable to load dex file: " + file, ex);
}
@@ -269,7 +273,7 @@
if (!ignoreDexFiles) {
try {
- dex = loadDexFile(file, optimizedDirectory);
+ dex = loadDexFile(file, optimizedDirectory, loader);
} catch (IOException suppressed) {
/*
* IOException might get thrown "legitimately" by the DexFile constructor if
@@ -295,16 +299,17 @@
}
/**
- * Constructs a {@code DexFile} instance, as appropriate depending
- * on whether {@code optimizedDirectory} is {@code null}.
+ * Constructs a {@code DexFile} instance, as appropriate depending on whether
+ * {@code optimizedDirectory} is {@code null}. An application image file may be associated with
+ * the {@code loader} if it is not null.
*/
- private static DexFile loadDexFile(File file, File optimizedDirectory)
+ private static DexFile loadDexFile(File file, File optimizedDirectory, ClassLoader loader)
throws IOException {
if (optimizedDirectory == null) {
- return new DexFile(file);
+ return new DexFile(file, loader);
} else {
String optimizedPath = optimizedPathFor(file, optimizedDirectory);
- return DexFile.loadDex(file.getPath(), optimizedPath, 0);
+ return DexFile.loadDex(file.getPath(), optimizedPath, 0, loader);
}
}