publicclassDexClassLoaderextendsBaseDexClassLoader { /** * Creates a {@code DexClassLoader} that finds interpreted and native * code. Interpreted classes are found in a set of DEX files contained * in Jar or APK files. * * <p>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, delimited by {@code File.pathSeparator}, which * defaults to {@code ":"} on Android * @param optimizedDirectory this parameter is deprecated and has no effect since API level 26. * @param librarySearchPath the list of directories containing native * libraries, delimited by {@code File.pathSeparator}; may be * {@code null} * @param parent the parent class loader */ publicDexClassLoader(String dexPath, String optimizedDirectory, String librarySearchPath, ClassLoader parent) { super(dexPath, null, librarySearchPath, parent); } }
if (dexPath == null) { thrownewNullPointerException("dexPath == null"); }
if (optimizedDirectory != null) { if (!optimizedDirectory.exists()) { thrownewIllegalArgumentException( "optimizedDirectory doesn't exist: " + optimizedDirectory); }
if (!(optimizedDirectory.canRead() && optimizedDirectory.canWrite())) { thrownewIllegalArgumentException( "optimizedDirectory not readable/writable: " + optimizedDirectory); } }
this.definingContext = definingContext;
ArrayList<IOException> suppressedExceptions = newArrayList<IOException>(); // save dexPath for BaseDexClassLoader this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory, suppressedExceptions, definingContext, isTrusted);
// Native libraries may exist in both the system and // application library paths, and we use this search order: // // 1. This class loader's library path for application libraries (librarySearchPath): // 1.1. Native library directories // 1.2. Path to libraries in apk-files // 2. The VM's library path from the system property for system libraries // also known as java.library.path // // This order was reversed prior to Gingerbread; see http://b/2933456. this.nativeLibraryDirectories = splitPaths(librarySearchPath, false); this.systemNativeLibraryDirectories = splitPaths(System.getProperty("java.library.path"), true); this.nativeLibraryPathElements = makePathElements(getAllNativeLibraryDirectories());
privatestatic Element[] makeDexElements(List<File> files, File optimizedDirectory, List<IOException> suppressedExceptions, ClassLoader loader, boolean isTrusted) { Element[] elements = newElement[files.size()]; intelementsPos=0; /* * Open all files and load the (direct or contained) dex files up front. */ // 遍历files,可以加载多个dex文件 for (File file : files) { if (file.isDirectory()) { // We support directories for looking up resources. Looking up resources in // directories is useful for running libcore tests. elements[elementsPos++] = newElement(file); } elseif (file.isFile()) { Stringname= file.getName();
DexFiledex=null; if (name.endsWith(DEX_SUFFIX)) { // Raw dex file (not inside a zip/jar). // 如果dex文件不是以zip或者jar包结尾就进入这个分支 // 动态加载要么加载dex文件或者zip文件或者jar包 try { dex = loadDexFile(file, optimizedDirectory, loader, elements); if (dex != null) { elements[elementsPos++] = newElement(dex, null); } } catch (IOException suppressed) { System.logE("Unable to load dex file: " + file, suppressed); suppressedExceptions.add(suppressed); } } else { // 如果dex文件是以zip或者jar包结尾就进入这个分支 try { dex = loadDexFile(file, optimizedDirectory, loader, elements); } catch (IOException suppressed) { /* * IOException might get thrown "legitimately" by the DexFile constructor if * the zip file turns out to be resource-only (that is, no classes.dex file * in it). * Let dex == null and hang on to the exception to add to the tea-leaves for * when findClass returns null. */ suppressedExceptions.add(suppressed); }
/* * 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. */ returnnewDexFile(sourcePathName, outputPathName, flags, loader, elements); }
privateDexFile(String sourceName, String outputName, int flags, ClassLoader loader, DexPathList.Element[] elements)throws IOException { if (outputName != null) { try { Stringparent=newFile(outputName).getParent(); if (Libcore.os.getuid() != Libcore.os.stat(parent).st_uid) { thrownewIllegalArgumentException("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 } }
// Verify we aren't holding the mutator lock, which could starve GC if we // have to generate or relocate an oat file. Thread* const self = Thread::Current(); Locks::mutator_lock_->AssertNotHeld(self); Runtime* const runtime = Runtime::Current();
std::unique_ptr<ClassLoaderContext> context; // If the class_loader is null there's not much we can do. This happens if a dex files is loaded // directly with DexFile APIs instead of using class loaders. if (class_loader == nullptr) { LOG(WARNING) << "Opening an oat file without a class loader. " << "Are you using the deprecated DexFile APIs?"; context = nullptr; } else { context = ClassLoaderContext::CreateContextForClassLoader(class_loader, dex_elements); }
// Load the dex files from the oat file. // 这里也不走,oat文件不存在 if (source_oat_file != nullptr) { ... }
// Fall back to running out of the original dex file if we couldn't load any // dex_files from the oat file. // 从这里开始时执行 // 如果oat文件不存在,尝试加载dex文件 if (dex_files.empty()) { if (oat_file_assistant.HasOriginalDexFiles()) { if (Runtime::Current()->IsDexFileFallbackEnabled()) { staticconstexprbool kVerifyChecksum = true; const ArtDexFileLoader dex_file_loader; // 这里是关键函数,dex路径往这里传了 if (!dex_file_loader.Open(dex_location, dex_location, Runtime::Current()->IsVerificationEnabled(), kVerifyChecksum, /*out*/ &error_msg, &dex_files)) { LOG(WARNING) << error_msg; error_msgs->push_back("Failed to open dex files from " + std::string(dex_location) + " because: " + error_msg); } } else { error_msgs->push_back("Fallback mode disabled, skipping dex files."); } } else { error_msgs->push_back("No original dex files found for dex location " + std::string(dex_location)); } }
// Opening CompactDex is only supported from vdex files. if (dex_file != nullptr && dex_file->IsCompactDexFile()) { *error_msg = StringPrintf("Opening CompactDex file '%s' is only supported from vdex files", location.c_str()); return nullptr; } return dex_file; }