dex文件加載步驟

dex通過DexClassLoader和PathClassLoader,其中PathClassLoader是應用使用的ClassLoader,DexClassLoader是用與加載指定的dex文件,
兩個ClassLoader代碼都比較簡單直接執(zhí)行父類(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,構造方法創(chuàng)建了,DexPathList類。
2族壳,findClass丢烘,findResource革为,findLibrary熬丧,getPackage 直接調(diào)用DexPathList中對應的方法
3,findClass:根據(jù)名稱查找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墨叛,循環(huán)PathListFile滑沧,根據(jù)文件后綴執(zhí)行ZipFile或者DexFile的構造方法,最終返回DexElement巍实。
關注loadDexFile

private static DexFile loadDexFile(File file, File optimizedDirectory)
            throws IOException {
        if (optimizedDirectory == null) {
            //PathClassLoader執(zhí)行
            return new DexFile(file); 
        } else {
            //DexClassLoader執(zhí)行
            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都調(diào)用了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的邏輯并帶有優(yōu)化操作哩牍,當傳入outputName時優(yōu)化后的代碼會放到這里棚潦。加載dex也會優(yōu)先使用優(yōu)化后的代碼。/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和環(huán)境變量組成的list膝昆。如果是PathClassLoader的時候就只有環(huán)境變量

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

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末丸边,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子荚孵,更是在濱河造成了極大的恐慌妹窖,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件收叶,死亡現(xiàn)場離奇詭異骄呼,居然都是意外死亡,警方通過查閱死者的電腦和手機判没,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門蜓萄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人澄峰,你說我怎么就攤上這事嫉沽。” “怎么了俏竞?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵绸硕,是天一觀的道長。 經(jīng)常有香客問我魂毁,道長玻佩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任漱牵,我火速辦了婚禮夺蛇,結果婚禮上,老公的妹妹穿的比我還像新娘酣胀。我一直安慰自己刁赦,他們只是感情好,可當我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布闻镶。 她就那樣靜靜地躺著甚脉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪铆农。 梳的紋絲不亂的頭發(fā)上牺氨,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天狡耻,我揣著相機與錄音,去河邊找鬼猴凹。 笑死夷狰,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的郊霎。 我是一名探鬼主播沼头,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼书劝!你這毒婦竟也來了进倍?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤购对,失蹤者是張志新(化名)和其女友劉穎猾昆,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體骡苞,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡垂蜗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了烙如。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片么抗。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖亚铁,靈堂內(nèi)的尸體忽然破棺而出蝇刀,到底是詐尸還是另有隱情,我是刑警寧澤徘溢,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布吞琐,位于F島的核電站,受9級特大地震影響然爆,放射性物質(zhì)發(fā)生泄漏站粟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一曾雕、第九天 我趴在偏房一處隱蔽的房頂上張望奴烙。 院中可真熱鬧,春花似錦剖张、人聲如沸切诀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽幅虑。三九已至,卻和暖如春顾犹,著一層夾襖步出監(jiān)牢的瞬間倒庵,已是汗流浹背褒墨。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留擎宝,地道東北人郁妈。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像绍申,于是被迫代替她去往敵國和親圃庭。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,914評論 2 355