public class DexClassLoader extends BaseDexClassLoader {
/**
* Creates a {@code DexClassLoader} that finds interpreted and native
<<<<<<< HEAD
* code. Interpreted classes are found in a set of dex files contained
* in jar or apk files.
*
* @param dexPath the list of jar/apk files containing classes and
* resources, delimited by {@code File.pathSeparator}, which
* defaults to {@code ":"} on Android
* @param optimizedDirectory directory where optimized dex files
* should be written; must not be {@code null}
* @param libraryPath the list of directories containing native
* libraries, delimited by {@code File.pathSeparator}; may be
* {@code null}
* @param parent the parent class loader
}
*/
public DexClassLoader(String dexPath, String optimizedDirectory,
String libraryPath, ClassLoader parent) {
super(dexPath, new File(optimizedDirectory), libraryPath, parent);
=======
* code. Interpreted classes are found in a set of DEX files contained
* in Jar or APK files.
*
* The path lists are separated using the character specified by the
* {@code path.separator} system property, which defaults to {@code :}.
*
* @param dexPath the list of jar/apk files containing classes and resources
* @param dexOutputDir directory where optimized DEX files should be
* written. This should be an application-private, writable directory.
* @param libPath the list of directories containing native libraries; may
* be null
* @param parent the parent class loader
*/
public DexClassLoader(String dexPath, String dexOutputDir, String libPath,
ClassLoader parent) {
super(parent);
if (dexPath == null || dexOutputDir == null) {
throw new NullPointerException();
}
mRawDexPath = dexPath;
mDexOutputPath = dexOutputDir;
mRawLibPath = libPath;
String[] dexPathList = mRawDexPath.split(":");
int length = dexPathList.length;
mFiles = new File[length];
mZips = new ZipFile[length];
mDexs = new DexFile[length];
/* open all Zip and DEX files up front */
for (int i = 0; i < length; i++) {
File pathFile = new File(dexPathList[i]);
mFiles[i] = pathFile;
if (pathFile.isFile()) {
if (!dexPathList[i].endsWith(".dex")) {
/*
* If the name doesn't end with ".dex" assume it's a zip
* file of some sort.
*/
try {
mZips[i] = new ZipFile(pathFile);
}
catch (IOException ioex) {
// expecting IOException and ZipException
//System.out.println("Failed opening '" + pathFile
// + "': " + ioex);
//ioex.printStackTrace();
}
}
/*
* If we got a zip file, we still need to extract out
* the dex file from it.
*/
try {
String outputName =
generateOutputName(dexPathList[i], mDexOutputPath);
mDexs[i] = DexFile.loadDex(dexPathList[i], outputName, 0);
} catch (IOException ioex) {
// It might be a resource-only zip.
//System.out.println("Failed to construct DexFile '"
// + pathFile + "': " + ioex);
}
}
}
/*
* Prep for native library loading.
*/
String pathList = System.getProperty("java.library.path", ".");
String pathSep = System.getProperty("path.separator", ":");
String fileSep = System.getProperty("file.separator", "/");
if (mRawLibPath != null) {
if (pathList.length() > 0) {
pathList += pathSep + mRawLibPath;
}
else {
pathList = mRawLibPath;
}
mLibPaths = pathList.split(pathSep);
length = mLibPaths.length;
// Add a '/' to the end so we don't have to do the property lookup
// and concatenation later.
for (int i = 0; i < length; i++) {
if (!mLibPaths[i].endsWith(fileSep))
mLibPaths[i] += fileSep;
if (VERBOSE_DEBUG)
System.out.println("Native lib path " +i+ ": "
+ mLibPaths[i]);
}
}
/**
* Convert a source path name and an output directory to an output
* file name.
*/
private static String generateOutputName(String sourcePathName,
String outputDir) {
StringBuilder newStr = new StringBuilder(80);
/* start with the output directory */
newStr.append(outputDir);
if (!outputDir.endsWith("/"))
newStr.append("/");
/* get the filename component of the path */
String sourceFileName;
int lastSlash = sourcePathName.lastIndexOf("/");
if (lastSlash < 0)
sourceFileName = sourcePathName;
else
sourceFileName = sourcePathName.substring(lastSlash+1);
/*
* Replace ".jar", ".zip", whatever with ".dex". We don't want to
* use ".odex", because the build system uses that for files that
* are paired with resource-only jar files. If the VM can assume
* that there's no classes.dex in the matching jar, it doesn't need
* to open the jar to check for updated dependencies, providing a
* slight performance boost at startup. The use of ".dex" here
* matches the use on files in /data/dalvik-cache.
*/
int lastDot = sourceFileName.lastIndexOf(".");
if (lastDot < 0)
newStr.append(sourceFileName);
else
newStr.append(sourceFileName, 0, lastDot);
newStr.append(".dex");
if (VERBOSE_DEBUG)
System.out.println("Output file will be " + newStr.toString());
return newStr.toString();
}
/**
* Finds a class. This method is called by {@code loadClass()} after the
* parent ClassLoader has failed to find a loaded class of the same name.
*
* @param name
* The name of the class to search for, in a human-readable form
* like "java.lang.String" or "java.net.URLClassLoader$3$1".
* @return the {@link Class} object representing the class
* @throws ClassNotFoundException
* if the class cannot be found
*/
@Override
protected Class> findClass(String name) throws ClassNotFoundException {
if (VERBOSE_DEBUG)
System.out.println("DexClassLoader " + this
+ ": findClass '" + name + "'");
int length = mFiles.length;
for (int i = 0; i < length; i++) {
if (VERBOSE_DEBUG)
System.out.println(" Now searching: " + mFiles[i].getPath());
if (mDexs[i] != null) {
String slashName = name.replace('.', '/');
Class clazz = mDexs[i].loadClass(slashName, this);
if (clazz != null) {
if (VERBOSE_DEBUG)
System.out.println(" found");
return clazz;
}
}
}
throw new ClassNotFoundException(name + " in loader " + this);
}
/**
* Finds a resource. This method is called by {@code getResource()} after
if (pack == null) {
* the parent ClassLoader has failed to find a loaded resource of the same
* name.
*
* @param name
* The name of the resource to find
* @return the location of the resource as a URL, or {@code null} if the
* resource is not found.
*/
@Override
protected URL findResource(String name) {
int length = mFiles.length;
for (int i = 0; i < length; i++) {
File pathFile = mFiles[i];
ZipFile zip = mZips[i];
if (zip.getEntry(name) != null) {
if (VERBOSE_DEBUG)
System.out.println(" found " + name + " in " + pathFile);
try {
// File.toURL() is compliant with RFC 1738 in always
// creating absolute path names. If we construct the
// URL by concatenating strings, we might end up with
// illegal URLs for relative names.
return new URL("jar:" + pathFile.toURL() + "!/" + name);
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
}
if (VERBOSE_DEBUG)
System.out.println(" resource " + name + " not found");
return null;
}
/**
* Finds a native library. This method is called after the parent
* ClassLoader has failed to find a native library of the same name.
*
* @param libname
* The name of the library to find
* @return the complete path of the library, or {@code null} if the library
* is not found.
*/
@Override
protected String findLibrary(String libname) {
String fileName = System.mapLibraryName(libname);
for (int i = 0; i < mLibPaths.length; i++) {
String pathName = mLibPaths[i] + fileName;
File test = new File(pathName);
if (test.exists()) {
if (VERBOSE_DEBUG)
System.out.println(" found " + libname);
return pathName;
}
}
if (VERBOSE_DEBUG)
System.out.println(" library " + libname + " not found");
return null;
}
/**
* Returns package information for the given package. Unfortunately, the
* DexClassLoader doesn't really have this information, and as a non-secure
* ClassLoader, it isn't even required to, according to the spec. Yet, we
* want to provide it, in order to make all those hopeful callers of
* myClass.getPackage().getName() happy. Thus we construct a
* Package object the first time it is being requested and fill most of the
* fields with dummy values. The Package object is then put into the
* ClassLoader's Package cache, so we see the same one next time. We don't
* create Package objects for null arguments or for the default package.
*
* There a limited chance that we end up with multiple Package objects
* representing the same package: It can happen when when a package is
* scattered across different JAR files being loaded by different
* ClassLoaders. Rather unlikely, and given that this whole thing is more or
* less a workaround, probably not worth the effort.
*
* @param name
* the name of the class
* @return the package information for the class, or {@code null} if there
* is not package information available for it
*/
@Override
protected Package getPackage(String name) {
if (name != null && !name.isEmpty()) {
synchronized(this) {
Package pack = super.getPackage(name);
pack = definePackage(name, "Unknown", "0.0", "Unknown",
"Unknown", "0.0", "Unknown", null);
}
return pack;
}
}
return null;
>>>>>>> ba4500230de2ac9d293c006cc2223b0794614b62
}
} |