新聞中心
繼插件化后,熱補(bǔ)丁技術(shù)在2015年開始爆發(fā),目前已經(jīng)是非常熱門的Android開發(fā)技術(shù)。其中比較著名的有淘寶的Dexposed、支付寶的AndFix以及Qzone的超級(jí)熱補(bǔ)丁方案。微信對(duì)熱補(bǔ)丁技術(shù)的研究并不算早,大約開始于2015年6月。經(jīng)過研究與嘗試現(xiàn)有的各個(gè)方案,我們發(fā)現(xiàn)它們都有著自身的一些局限性。微信最終采用不同于它們的技術(shù)方案,走出了自己的實(shí)踐演進(jìn)之路。

另外一方面,技術(shù)應(yīng)當(dāng)只是熱補(bǔ)丁方案中的一環(huán)。隨著對(duì)熱補(bǔ)丁的多次嘗試與應(yīng)用,微信建立起自身的流程規(guī)范,同時(shí)也不斷的嘗試拓展它的應(yīng)用場景。通過本文,我希望大家不僅能夠全面的了解各項(xiàng)熱補(bǔ)丁技術(shù)的優(yōu)缺點(diǎn),同時(shí)也能對(duì)它的應(yīng)用場景有著更加全面的認(rèn)識(shí)。在此基礎(chǔ)上,大家或許能更容易的決定是否在自己的項(xiàng)目中使用熱補(bǔ)丁技術(shù),以及應(yīng)當(dāng)如何使用它。
一.為什么需要熱補(bǔ)丁
熱補(bǔ)?。?/strong>讓應(yīng)用能夠在無需重新安裝的情況實(shí)現(xiàn)更新,幫助應(yīng)用快速建立動(dòng)態(tài)修復(fù)能力。
從上面的定義來看,熱補(bǔ)丁節(jié)省Android大量應(yīng)用市場發(fā)布的時(shí)間。同時(shí)用戶也無需重新安裝,只要上線就能無感知的更新??雌饋砗苊篮?,這是否可以意味我們可以盡量使用補(bǔ)丁來代替發(fā)布呢?事實(shí)上,熱補(bǔ)丁技術(shù)當(dāng)前依然存在它的局限性,主要表現(xiàn)在以下幾點(diǎn):
- 補(bǔ)丁只能針對(duì)單一客戶端版本,隨著版本差異變大補(bǔ)丁體積也會(huì)增大;
- 補(bǔ)丁不能支持所有的修改,例如AndroidManifest;
- 補(bǔ)丁無論對(duì)代碼還是資源的更新成功率都無法達(dá)到100%。
既然補(bǔ)丁技術(shù)無法完全代替升級(jí),那它適合使用在哪些場景呢?
二. 輕量而快速的升級(jí)
熱補(bǔ)丁技術(shù)也可以理解為一個(gè)動(dòng)態(tài)修改代碼與資源的通道,它適合于修改量較少的情況。以微信的多次發(fā)布為例,補(bǔ)丁大小均在300K以內(nèi),它相對(duì)于傳統(tǒng)的發(fā)布有著很大的優(yōu)勢。
以Android用戶的升級(jí)習(xí)慣,即使是相對(duì)活躍的微信也需要10天以上的時(shí)間去覆蓋50%的用戶。使用補(bǔ)丁技術(shù),我們能做到1天覆蓋70%以上。這也是基于補(bǔ)丁體積較小,可以直接使用移動(dòng)網(wǎng)絡(luò)下載更新。
正因如此,補(bǔ)丁技術(shù)非常適合使用在灰度階段。在過去,我們需要在正式發(fā)布前保證所有嚴(yán)重的問題都已經(jīng)得到修復(fù),這通常需要我們經(jīng)過三次以上的灰度過程,而且無法快速的驗(yàn)證這些問題在同一批用戶的修復(fù)效果。利用熱補(bǔ)丁技術(shù),我們可以快速對(duì)同一批用戶驗(yàn)證修復(fù)效果,這大大縮短我們的發(fā)布流程。
若發(fā)布版本出現(xiàn)問題或緊急漏洞,傳統(tǒng)方式需要單獨(dú)灰度驗(yàn)證修改,然后重新發(fā)布新的版本。利用補(bǔ)丁技術(shù),我們只需要先上線小部分用戶驗(yàn)證修改的效果,***再全量上線即可。但是此種發(fā)布對(duì)線上用戶影響較大, 我們需要謹(jǐn)慎而為。本著對(duì)用戶負(fù)責(zé)的態(tài)度,發(fā)布補(bǔ)丁等同于發(fā)布版本,它也應(yīng)該嚴(yán)格執(zhí)行完整的測試與上線流程。
總的來說,補(bǔ)丁技術(shù)可以降低開發(fā)成本,縮短開發(fā)周期,實(shí)現(xiàn)輕量而快速的升級(jí)。
三. 遠(yuǎn)端調(diào)試
一入Android深似海,Android開發(fā)的另外一個(gè)痛是機(jī)型的碎片化。我們也許都會(huì)遇到"本地不復(fù)現(xiàn)","日志查不出","聯(lián)系用戶不鳥你"的煩惱。所以補(bǔ)丁機(jī)制非常適合使用在遠(yuǎn)端調(diào)試上。即我們需要具備只特定用戶發(fā)送補(bǔ)丁的能力,這對(duì)我們查找問題非常有幫助。
利用補(bǔ)丁技術(shù),我們避免了騷擾用戶而默默的為用戶解決問題。當(dāng)然這也需要非常嚴(yán)格的權(quán)限管理,以防惡意或隨意使用。
四. 數(shù)據(jù)統(tǒng)計(jì)
數(shù)據(jù)統(tǒng)計(jì)在微信中也占據(jù)著非常重要的位置,我們也非常希望將熱補(bǔ)丁與數(shù)據(jù)統(tǒng)計(jì)結(jié)合的更好。事實(shí)上,熱補(bǔ)丁無論在普通的數(shù)據(jù)統(tǒng)計(jì)還是ABTest都有著非常大的優(yōu)勢。例如若我想對(duì)同一批用戶做兩種test, 傳統(tǒng)方式無法讓這批用戶去安裝兩個(gè)版本。使用補(bǔ)丁技術(shù),我們可以方便的對(duì)同一批用戶更換補(bǔ)丁版本。
在數(shù)據(jù)統(tǒng)計(jì)之路,如何與補(bǔ)丁技術(shù)結(jié)合的更好,更加精準(zhǔn)的控制樣本人數(shù)與比例,這也是微信當(dāng)前努力發(fā)展的一個(gè)方向。
五. 其他
事實(shí)上,Android官方也使用熱補(bǔ)丁技術(shù)實(shí)現(xiàn)Instant Run。它分為Hot Swap、Warm Swap與Cold Swap三種方式,大家可以參考英文介紹,也可以看參考文章中的翻譯稿。***的Instant App應(yīng)該也是采用類似的原理,但是Google Play是不允許下發(fā)代碼的,這個(gè)海外App需要注意一下。
六.微信熱補(bǔ)丁技術(shù)的演進(jìn)之路
在了解補(bǔ)丁技術(shù)可以與適合做什么之后,我們回到技術(shù)本身。由于Dexposed無法支持全平臺(tái),并不適合應(yīng)用到商業(yè)產(chǎn)品中。所以這里我們只簡單介紹Andfix、Qzone、微信幾套方案的實(shí)現(xiàn),以及它們方案面臨著的問題,大家也可以參考資料中的各大熱補(bǔ)丁方案分析和比較一文。
1. AndFix
AndFix采用native hook的方式,這套方案直接使用dalvik_replaceMethod替換class中方法的實(shí)現(xiàn)。由于它并沒有整體替換class, 而field在class中的相對(duì)地址在class加載時(shí)已確定,所以AndFix無法支持新增或者刪除filed的情況(通過替換init與clinit只可以修改field的數(shù)值)。
也正因如此,Andfix可以支持的補(bǔ)丁場景相對(duì)有限,僅僅可以使用它來修復(fù)特定問題。結(jié)合之前的發(fā)布流程,我們更希望補(bǔ)丁對(duì)開發(fā)者是不感知的,即他不需要清楚這個(gè)修改是對(duì)補(bǔ)丁版本還是正式發(fā)布版本(事實(shí)上我們也是使用git分支管理+cherry-pick方式)。另一方面,使用native替換將會(huì)面臨比較復(fù)雜的兼容性問題。
相比其他方案,AndFix的***優(yōu)點(diǎn)在于立即生效。事實(shí)上,AndFix的實(shí)現(xiàn)與Instant Run的熱插拔有點(diǎn)類似,但是由于使用場景的限制,微信在最初期已排除使用這一方案。
2. Qzone
Qzone方案并沒有開源,但在github上的Nuwa采用了相同的方式。這個(gè)方案使用classloader的方式,能實(shí)現(xiàn)更加友好的類替換。而且這與我們加載Multidex的做法相似,能基本保證穩(wěn)定性與兼容性。具體原理在這里不再細(xì)說,大家可以參考"安卓App熱補(bǔ)丁動(dòng)態(tài)修復(fù)技術(shù)介紹"這篇文章。
本方案為了解決unexpected DEX problem異常而采用插樁的方式,從而規(guī)避問題的出現(xiàn)。事實(shí)上,Android系統(tǒng)的這些檢查規(guī)則是非常有意義的,這會(huì)導(dǎo)致Qzone方案在Dalvik與Art都會(huì)產(chǎn)生一些問題。
Dalvik; 在dexopt過程,若class verify通過會(huì)寫入pre-verify標(biāo)志,在經(jīng)過optimize之后再寫入odex文件。這里的optimize主要包括inline以及quick指令優(yōu)化等。
若采用插樁導(dǎo)致所有類都非preverify,這導(dǎo)致verify與optimize操作會(huì)在加載類時(shí)觸發(fā)。這會(huì)有一定的性能損耗,微信分別采用插樁與不插樁兩種方式做過兩種測試,一是連續(xù)加載700個(gè)50行左右的類,一是統(tǒng)計(jì)微信整個(gè)啟動(dòng)完成的耗時(shí)。
平均每個(gè)類verify+optimize(跟類的大小有關(guān)系)的耗時(shí)并不長,而且這個(gè)耗時(shí)每個(gè)類只有一次。但由于啟動(dòng)時(shí)會(huì)加載大量的類,在這個(gè)情況影響還是比較大。
Art; Art采用了新的方式,插樁對(duì)代碼的執(zhí)行效率并沒有什么影響。但是若補(bǔ)丁中的類出現(xiàn)修改類變量或者方法,可能會(huì)導(dǎo)致出現(xiàn)內(nèi)存地址錯(cuò)亂的問題。為了解決這個(gè)問題我們需要將修改了變量、方法以及接口的類的父類以及調(diào)用這個(gè)類的所有類都加入到補(bǔ)丁包中。這可能會(huì)帶來補(bǔ)丁包大小的急劇增加。
這里是因?yàn)樵赿ex2oat時(shí)fast*已經(jīng)將類能確定的各個(gè)地址寫死。如果運(yùn)行時(shí)補(bǔ)丁包的地址出現(xiàn)改變,原始類去調(diào)用時(shí)就會(huì)出現(xiàn)地址錯(cuò)亂。這里說的可能不夠詳細(xì),事實(shí)上微信當(dāng)時(shí)為了查清這兩個(gè)問題,也花費(fèi)了一定的時(shí)間將Dalvik跟Art的流程基本搞透。若大家對(duì)這里感興趣,后續(xù)在單獨(dú)的文章詳細(xì)論述。
總的來說,Qzone方案好處在于開發(fā)透明,簡單,這一套方案目前的應(yīng)用成功率也是***的,但在補(bǔ)丁包大小與性能損耗上有一定的局限性。特別是無論我們是否真正應(yīng)用補(bǔ)丁,都會(huì)因?yàn)椴鍢秾?dǎo)致對(duì)程序運(yùn)行時(shí)的性能產(chǎn)生影響。微信對(duì)于性能要求較高,所以我們也沒有采用這套方案。
3. 微信熱補(bǔ)丁方案
有沒有那么一種方案,能做到開發(fā)透明,但是卻沒有Qzone方案的缺陷呢?Instant Run的冷插拔與buck的exopackage或許能給我們靈感,它們的思想都是全量替換新的Dex。即我們完全使用了新的Dex,那樣既不出現(xiàn)Art地址錯(cuò)亂的問題,在Dalvik也無須插樁。當(dāng)然考慮到補(bǔ)丁包的體積,我們不能直接將新的Dex放在里面。但我們可以將新舊兩個(gè)Dex的差異放到補(bǔ)丁包中,最簡單我們可以采用BsDiff算法。
簡單來說,在編譯時(shí)通過新舊兩個(gè)Dex生成差異patch.dex。在運(yùn)行時(shí),將差異patch.dex重新跟原始安裝包的舊Dex還原為新的Dex。這個(gè)過程可能比較耗費(fèi)時(shí)間與內(nèi)存,所以我們是單獨(dú)放在一個(gè)后臺(tái)進(jìn)程:patch中。為了補(bǔ)丁包盡量的小,微信自研了DexDiff算法,它深度利用Dex的格式來減少差異的大小。它的粒度是Dex格式的每一項(xiàng),可以充分利用原本Dex的信息,而BsDiff的粒度是文件,AndFix/Qzone的粒度為class。
這塊后面我希望后面用單獨(dú)的文章來講述,這里先做一個(gè)鋪墊,大致的效果如下圖。在最極端的情況,由于利用了原本dex的信息完全替換一個(gè)13M的Dex,我們的補(bǔ)丁大小也僅僅只有6.6M。
但是這套方案并非沒有缺點(diǎn),它帶來的問題有兩個(gè):
- 占用Rom體積;這邊大約是你所修改Dex大小的1.5倍(Dex壓縮成jar的大小加上生成的dexopt文件大小)。
- 一個(gè)額外的合成過程;雖然我們單獨(dú)放在一個(gè)進(jìn)程上處理,但是合成時(shí)間的長短與內(nèi)存消耗也會(huì)影響最終的成功率(與修改Dex大小、補(bǔ)丁大小相關(guān))。
微信的熱補(bǔ)丁方案叫做Tinker,也算緬懷一下Dota中的地精修補(bǔ)匠,希望能做到***刷新。
限于篇幅,這里對(duì)Dex、library以及資源的更多技術(shù)細(xì)節(jié)并沒有詳細(xì)的論述,這里希望放在后面的單獨(dú)文章中。我們***從整體比較一下這幾種方案:
若不care性能損耗與補(bǔ)丁包大小,Qzone方案是最簡單且成功率***的方案(沒有單獨(dú)的合成過程)。相對(duì)Tinker來說,它的占用Rom體積也更小。另一方面,Qzone與Tinker的成功率當(dāng)前大約相差3%左右。
事實(shí)上,一個(gè)完整的框架應(yīng)該也是一個(gè)容易使用的框架。Tinker對(duì)補(bǔ)丁版本管理、進(jìn)程管理、安全校驗(yàn)等都有著很好的支持。同時(shí)我們也支持gradle與命名行兩種接入方式。希望在不久的將來,它可以很快的跟大家見面。
七.微信的熱補(bǔ)丁應(yīng)用現(xiàn)狀
上一章節(jié)我們簡單比較了各個(gè)熱補(bǔ)丁的技術(shù)方案,它們解決了如何生成與加載補(bǔ)丁包的問題。但一個(gè)完善的熱補(bǔ)丁系統(tǒng)不應(yīng)該僅限于此,它還需要包括以下幾個(gè)方面:
網(wǎng)絡(luò)通道;這里要解決的問題是決定補(bǔ)丁以何種方式推送給哪部分的用戶。
上線與后臺(tái)管理平臺(tái);這里主要包括熱補(bǔ)丁的上線管理,歷史管理以及上報(bào)分析,報(bào)警監(jiān)控等;
1. 網(wǎng)絡(luò)通道現(xiàn)狀
網(wǎng)絡(luò)通道負(fù)責(zé)的將補(bǔ)丁包交付給用戶,這個(gè)包括特定用戶與全量用戶兩種情況。事實(shí)上,微信當(dāng)前針對(duì)熱補(bǔ)丁有以下三種通道更新:
- pull通道; 在登陸/24小時(shí)等時(shí)機(jī),通過pull方式查詢后臺(tái)是否有對(duì)應(yīng)的補(bǔ)丁包更新,這也是我們最常用的方式;
- 指定版本的push通道; 針對(duì)版本的通道,在緊急情況下,我們可以在一個(gè)小時(shí)內(nèi)向所有用戶下發(fā)補(bǔ)丁包更新。
- 指定特定用戶的push通道;對(duì)特定用戶或用戶組做遠(yuǎn)程調(diào)試。
事實(shí)上,對(duì)于大部分的應(yīng)用來說,假設(shè)不實(shí)現(xiàn)push通道,CDN+pull通道實(shí)現(xiàn)起來還是較為容易。
2. 上線與管理平臺(tái)現(xiàn)狀
上線與管理平臺(tái)主要為了快速上線,管理歷史記錄,以及監(jiān)控補(bǔ)丁的運(yùn)行情況等(界面比較丑陋,因?yàn)槲覀兡居忻拦ぐ?。
事實(shí)上,微信發(fā)布熱補(bǔ)丁是非常慎重的。它整個(gè)發(fā)布流程與升級(jí)版本是保持一致的,也必須修改版本號(hào)、經(jīng)過嚴(yán)格的完整測試流程等。我們也會(huì)通過灰度的方式上線,同時(shí)監(jiān)控補(bǔ)丁版本的各個(gè)指標(biāo)。這里的為了完整的監(jiān)控補(bǔ)丁的情況,我們做的工作有:
- 1分鐘粒度的每小時(shí)/每天的各版本累積用戶,及時(shí)監(jiān)控補(bǔ)丁版本的人數(shù)與活躍;
- 3分鐘粒度的Crash統(tǒng)計(jì),基準(zhǔn)版本與補(bǔ)丁版本的Crash每小時(shí)/每天的兩個(gè)維度對(duì)照;
- 10分鐘粒度的補(bǔ)丁監(jiān)控信息上報(bào)。
3. 補(bǔ)丁成功率現(xiàn)狀
應(yīng)用成功率= 補(bǔ)丁版本人數(shù)/補(bǔ)丁發(fā)布前該版本人數(shù)
由于可能存在基準(zhǔn)或補(bǔ)丁版本用戶安裝了其他版本,所以本統(tǒng)計(jì)結(jié)果應(yīng)略為偏低,但它能現(xiàn)實(shí)的反應(yīng)補(bǔ)丁的線上覆蓋情況。
使用Qzone方案,微信補(bǔ)丁在10天后的應(yīng)用成功率大約在98.5%左右。使用Tinker大約只有95.5%左右,主要原因在于空間不足以及后臺(tái)進(jìn)程被殺。在這里我們也在嘗試使用重試的方式以及降低合成的耗時(shí)與內(nèi)存,從而提升成功率。
熱補(bǔ)丁技術(shù)發(fā)展的很快,Android推出的Instant App也令人期待。但是在國內(nèi),似乎我們還是指望自己更靠譜一點(diǎn)。每一個(gè)的應(yīng)用的需求都不太一致,這里大致講了一些微信的實(shí)踐經(jīng)驗(yàn),希望對(duì)大家有幫助。
八.未來工作
隨著微信部門內(nèi)從“單APP”向“多APP”演進(jìn),微信也正在邁入開源化的開發(fā)實(shí)踐。我們希望將各個(gè)功能組件化,從而做可以到快速復(fù)制與應(yīng)用。微信的熱補(bǔ)丁框架“Tinker”當(dāng)前也在經(jīng)歷從微信分離,又合入到微信的過程。希望在不久的將來,我們也可以將“Tinker”以及微信中一些其他的組件開源出去。
我們也希望可以找一些App作為內(nèi)測,給我們提供寶貴的意見。若對(duì)微信的Tinker方案感興趣的用戶,可以單獨(dú)發(fā)消息或在文章末留言注明姓名、所在公司以及負(fù)責(zé)的App,我們希望挑選部分產(chǎn)品作為內(nèi)測。
網(wǎng)站標(biāo)題:微信Android熱補(bǔ)丁實(shí)踐演進(jìn)之路
當(dāng)前網(wǎng)址:http://fisionsoft.com.cn/article/dpeoshh.html


咨詢
建站咨詢
