Android熱更新四:熱修復(fù)機制

很早之前就想深入的研究和學習一下熱修復(fù)鞋邑,由于時間的原因一直拖著洼滚,現(xiàn)在才執(zhí)筆弄起來瞒渠。


Android而更新系列:
Android熱更新一:JAVA的類加載機制
Android熱更新二:理解Java反射
Android熱更新三:Android類加載機制
Android熱更新四:熱修復(fù)機制
Android熱更新五:四大熱修復(fù)方案分析
Android熱更新六:Qzone熱更新原理
Android熱更新七:Tinker熱更新原理
Android熱更新八:AndFix熱更新原理
Android熱更新九:Robust熱更新原理
Android熱更新十:自己寫一個Android熱修復(fù)


熱修復(fù)機制

之前已經(jīng)了解了Android類加載機制,知道在DexPathList里有個dexElements的數(shù)組
源碼中官方注釋

    /**
     * List of dex/resource (class path) elements.
     * Should be called pathElements, but the Facebook app uses reflection
     * to modify 'dexElements' (http://b/7726934).
     */
    private final Element[] dexElements;

熱修復(fù)就是利用dexElements的順序來做文章疑俭,當一個補丁的patch.dex放到了dexElements的第一位粮呢,那么當加載一個bug類時,發(fā)現(xiàn)在patch.dex中钞艇,則直接加載這個類啄寡,原來的bug類可能就被覆蓋了

看下PathClassLoader代碼

public class PathClassLoader extends BaseDexClassLoader {
 
    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代碼

public class DexClassLoader extends BaseDexClassLoader {
 
    public DexClassLoader(String dexPath, String optimizedDirectory, String libraryPath, ClassLoader parent) {
        super(dexPath, new File(optimizedDirectory), libraryPath, parent);
    }
}

兩個ClassLoader就兩三行代碼,只是調(diào)用了父類的構(gòu)造函數(shù).

public class BaseDexClassLoader extends ClassLoader {
    private final DexPathList pathList;
 
    public BaseDexClassLoader(String dexPath, File optimizedDirectory,
            String libraryPath, ClassLoader parent) {
        super(parent);
        this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
    }
 
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
        Class c = pathList.findClass(name, suppressedExceptions);
        if (c == null) {
            ClassNotFoundException cnfe = new ClassNotFoundException("Didn't find class \"" + name + "\" on path: " + pathList);
            for (Throwable t : suppressedExceptions) {
                cnfe.addSuppressed(t);
            }
            throw cnfe;
        }
        return c;
    }

在BaseDexClassLoader 構(gòu)造函數(shù)中創(chuàng)建一個DexPathList類的實例,這個DexPathList的構(gòu)造函數(shù)會創(chuàng)建一個dexElements 數(shù)組

public DexPathList(ClassLoader definingContext, String dexPath, String libraryPath, File optimizedDirectory) {
        ... 
        this.definingContext = definingContext;
        ArrayList<IOException> suppressedExceptions = new ArrayList<IOException>();
        //創(chuàng)建一個數(shù)組
        this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory, suppressedExceptions);
        ... 
    }

然后BaseDexClassLoader 重寫了findClass方法,調(diào)用了pathList.findClass,跳到DexPathList類中.

/* package */final class DexPathList {
    ...
    public Class findClass(String name, List<Throwable> suppressed) {
            //遍歷該數(shù)組
        for (Element element : dexElements) {
            //初始化DexFile
            DexFile dex = element.dexFile;
 
            if (dex != null) {
                //調(diào)用DexFile類的loadClassBinaryName方法返回Class實例
                Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed);
                if (clazz != null) {
                    return clazz;
                }
            }
        }       
        return null;
    }
    ...
} 

會遍歷這個數(shù)組,然后初始化DexFile哩照,如果DexFile不為空那么調(diào)用DexFile類的loadClassBinaryName方法返回Class實例.
歸納上面的話就是:ClassLoader會遍歷這個數(shù)組,然后加載這個數(shù)組中的dex文件.
而ClassLoader在加載到正確的類之后,就不會再去加載有Bug的那個類了,我們把這個正確的類放在Dex文件中,讓這個Dex文件排在dexElements數(shù)組前面即可.

CLASS_ISPREVERIFIED問題

根據(jù)QQ空間談到的在虛擬機啟動的時候挺物,在verify選項被打開的時候,如果static方法飘弧、private方法识藤、構(gòu)造函數(shù)等,其中的直接引用(第一層關(guān)系)到的類都在同一個dex文件中次伶,那么該類就會被打上CLASS_ISPREVERIFIED標志痴昧,且一旦類被打上CLASS_ISPREVERIFIED標志其他dex就不能再去替換這個類。所以一定要想辦法去阻止類被打上CLASS_ISPREVERIFIED標志冠王。

為了阻止類被打上CLASS_ISPREVERIFIED標志赶撰,QQ空間開發(fā)團隊提出了一個方法是先將一個預(yù)備好的hack.dex加入到dexElements的第一項,讓后面的dex的所有類都引用hack.dex其中的一個類,這樣原來的class1.dex豪娜、class2.dex餐胀、class3.dex中的所有類都引用了hack.dex的類,所以其中的都不會打上CLASS_ISPREVERIFIED標志瘤载。

Qzon團隊的 安卓App熱補丁動態(tài)修復(fù)技術(shù)介紹
(這個一定要看!!! 他是熱修復(fù)元老級文章,也是本文重點抄襲對象??????)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末否灾,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子惕虑,更是在濱河造成了極大的恐慌坟冲,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件溃蔫,死亡現(xiàn)場離奇詭異健提,居然都是意外死亡,警方通過查閱死者的電腦和手機伟叛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門私痹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人统刮,你說我怎么就攤上這事紊遵。” “怎么了侥蒙?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵暗膜,是天一觀的道長。 經(jīng)常有香客問我鞭衩,道長学搜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任论衍,我火速辦了婚禮瑞佩,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘坯台。我一直安慰自己炬丸,他們只是感情好,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布蜒蕾。 她就那樣靜靜地躺著稠炬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪滥搭。 梳的紋絲不亂的頭發(fā)上酸纲,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天,我揣著相機與錄音瑟匆,去河邊找鬼闽坡。 笑死栽惶,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的疾嗅。 我是一名探鬼主播外厂,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼代承!你這毒婦竟也來了汁蝶?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤论悴,失蹤者是張志新(化名)和其女友劉穎掖棉,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體膀估,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡幔亥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了察纯。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片帕棉。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖饼记,靈堂內(nèi)的尸體忽然破棺而出香伴,到底是詐尸還是另有隱情,我是刑警寧澤具则,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布即纲,位于F島的核電站,受9級特大地震影響博肋,放射性物質(zhì)發(fā)生泄漏崇裁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一束昵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧葛峻,春花似錦锹雏、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至采记,卻和暖如春佣耐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背唧龄。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工兼砖, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓讽挟,卻偏偏與公主長得像懒叛,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子耽梅,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容