美文网首页
dex文件加载步骤

dex文件加载步骤

作者: ben大福 | 来源:发表于2020-08-25 15:47 被阅读0次

dex通过DexClassLoader和PathClassLoader,其中PathClassLoader是应用使用的ClassLoader,DexClassLoader是用与加载指定的dex文件,
两个ClassLoader代码都比较简单直接执行父类(BaseDexClassLoader)方法

PathClassLoader.java
public PathClassLoader(String dexPath, ClassLoader parent) {
        super(dexPath, null, null, parent);
}
public PathClassLoader(String dexPath, String libraryPath,
            ClassLoader parent) {
        super(dexPath, null, libraryPath, parent);
}
DexClassLoader.java
public DexClassLoader(String dexPath, String optimizedDirectory,
            String libraryPath, ClassLoader parent) {
        super(dexPath, new File(optimizedDirectory), libraryPath, parent);
    }
BaseDexClassLoader.java
public BaseDexClassLoader(String dexPath, File optimizedDirectory,
            String libraryPath, ClassLoader parent) {
        super(parent);
        this.originalPath = dexPath;
        this.pathList =
            new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
    }

 @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        Class clazz = pathList.findClass(name);
        ....
        return clazz;
  }

  @Override
  protected URL findResource(String name) {
          return pathList.findResource(name);
  }
    @Override
    protected Enumeration<URL> findResources(String name) {
        return pathList.findResources(name);
    }
    @Override
    public String findLibrary(String name) {
        return pathList.findLibrary(name);
    }

 @Override
    protected synchronized Package getPackage(String name) {
        if (name != null && !name.isEmpty()) {
            Package pack = super.getPackage(name);
            if (pack == null) {
                pack = definePackage(name, "Unknown", "0.0", "Unknown",
                        "Unknown", "0.0", "Unknown", null);
            }
            return pack;
        }
        return null;
    }

1,构造方法创建了,DexPathList类。
2,findClass,findResource,findLibrary,getPackage 直接调用DexPathList中对应的方法
3,findClass:根据名称查找Class, findResource查找资源,findLibrary查找native library路径,getPackage 定义类名

下面查看DexPathList构造方法

public DexPathList(ClassLoader definingContext, String dexPath,
            String libraryPath, File optimizedDirectory) {
         ···
        this.definingContext = definingContext;
        this.dexElements =
            makeDexElements(splitDexPath(dexPath), optimizedDirectory);
        this.nativeLibraryDirectories = splitLibraryPath(libraryPath);
    }

前面都是安全校验,关键在于DexPathList维护了dexElements和nativeLibraryDirectories
其中dexElements存储了dex的文件路径或zip或dex,下面是Element的属性

class Element {
        public final File file;
        public final ZipFile zipFile;
        public final DexFile dexFile;
}

nativeLibraryDirectories则是naive库存储的路径
下面关注makeDexElements和splitLibraryPath方法

dexElements 生成

private static ArrayList<File> splitDexPath(String path) {
        return splitPaths(path, null, false);
    }
    private static ArrayList<File> splitPaths(String path1, String path2,
            boolean wantDirectories) {
        ArrayList<File> result = new ArrayList<File>();
        splitAndAdd(path1, wantDirectories, result);
        splitAndAdd(path2, wantDirectories, result);
        return result;
    }
  private static void splitAndAdd(String path, boolean wantDirectories,
            ArrayList<File> resultList) {
        if (path == null) {
            return;
        }
        String[] strings = path.split(Pattern.quote(File.pathSeparator));
        for (String s : strings) {
            File file = new File(s);
            if (! (file.exists() && file.canRead())) {
                continue;
            }
            /*
             * Note: There are other entities in filesystems than
             * regular files and directories.
             */
            if (wantDirectories) {
                if (!file.isDirectory()) {
                    continue;
                }
            } else {
                if (!file.isFile()) {
                    continue;
                }
            }
            resultList.add(file);
        }
    }

将path以“:”分开,返回文件列表

private static Element[] makeDexElements(ArrayList<File> files,
            File optimizedDirectory) {
···
for (File file : files) {
if (name.endsWith(DEX_SUFFIX)) {
                // Raw dex file (not inside a zip/jar).
                try {
                    dex = loadDexFile(file, optimizedDirectory);
                } catch (IOException ex) {
                    System.logE("Unable to load dex file: " + file, ex);
                }
            } else if (name.endsWith(APK_SUFFIX) || name.endsWith(JAR_SUFFIX)
                    || name.endsWith(ZIP_SUFFIX)) {
                try {
                    zip = new ZipFile(file);
                } catch (IOException ex) {
                    /*
                     * Note: ZipException (a subclass of IOException)
                     * might get thrown by the ZipFile constructor
                     * (e.g. if the file isn't actually a zip/jar
                     * file).
                     */
                    System.logE("Unable to open zip file: " + file, ex);
                }
                try {
                    dex = loadDexFile(file, optimizedDirectory);
                } catch (IOException ignored) {
                    /*
                     * 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). Safe to just ignore
                     * the exception here, and let dex == null.
                     */
                }
            } else {
                System.logW("Unknown file type for: " + file);
            }
}
···
return elements.toArray(new Element[elements.size()]);
}

1,循环PathListFile,根据文件后缀执行ZipFile或者DexFile的构造方法,最终返回DexElement。
关注loadDexFile

private static DexFile loadDexFile(File file, File optimizedDirectory)
            throws IOException {
        if (optimizedDirectory == null) {
            //PathClassLoader执行
            return new DexFile(file); 
        } else {
            //DexClassLoader执行
            String optimizedPath = optimizedPathFor(file, optimizedDirectory);
            return DexFile.loadDex(file.getPath(), optimizedPath, 0);
        }
    }
static public DexFile loadDex(String sourcePathName, String outputPathName,
        int flags) throws IOException {
        return new DexFile(sourcePathName, outputPathName, flags);
    }
public DexFile(String fileName) throws IOException {
        mCookie = openDexFile(fileName, null, 0);
        mFileName = fileName;
        guard.open("close");
        //System.out.println("DEX FILE cookie is " + mCookie);
    }
private DexFile(String sourceName, String outputName, int flags) throws IOException {
        mCookie = openDexFile(sourceName, outputName, flags);
        mFileName = sourceName;
        guard.open("close");
    }

两个ClassLoader都调用了DexFile的方法openDexFile方法。

vm/native/dalvik_system_DexFile.cpp
static void Dalvik_dalvik_system_DexFile_openDexFile(const u4* args,
    JValue* pResult){
···
if (hasDexExtension(sourceName)
            && dvmRawDexFileOpen(sourceName, outputName, &pRawDexFile, false) == 0) {
        ALOGV("Opening DEX file '%s' (DEX)", sourceName);
        pDexOrJar = (DexOrJar*) malloc(sizeof(DexOrJar));
        pDexOrJar->isDex = true;
        pDexOrJar->pRawDexFile = pRawDexFile;
        pDexOrJar->pDexMemory = NULL;
    } else if (dvmJarFileOpen(sourceName, outputName, &pJarFile, false) == 0) {
        ALOGV("Opening DEX file '%s' (Jar)", sourceName);
        pDexOrJar = (DexOrJar*) malloc(sizeof(DexOrJar));
        pDexOrJar->isDex = false;
        pDexOrJar->pJarFile = pJarFile;
        pDexOrJar->pDexMemory = NULL;
    } 
}
···

native层是主要加载dex的逻辑并带有优化操作,当传入outputName时优化后的代码会放到这里。加载dex也会优先使用优化后的代码。/data/dalvik-cache或者传入的路径
native步骤

nativeLibraryDirectories 生成

        ArrayList<File> result = splitPaths(
                path, System.getProperty("java.library.path", "."), true);
        return result.toArray(new File[result.size()]);

native很简单只是传入的nativepath和环境变量组成的list。如果是PathClassLoader的时候就只有环境变量

参考:https://zhuanlan.zhihu.com/p/80629979

相关文章

网友评论

      本文标题:dex文件加载步骤

      本文链接:https://www.haomeiwen.com/subject/byznjktx.html