轉(zhuǎn)載Atlas:手淘Native容器化框架和思考-玄黎

在剛剛過去的云棲大會上,手淘宣布其移動容器化框架Atlas將于2017年年初開源冈爹,對這個框架,在過去團隊對外部做過一些分享欧引,外界也一直對其十分關(guān)注频伤,到現(xiàn)在它終于即將開源了。
本文將介紹Atlas的設(shè)計思路和手淘對容器化维咸、組件化和動態(tài)化上的思考,主要內(nèi)容來自阿里巴巴資深技術(shù)專家倪生華(玄黎)在2016杭州云棲大會上的分享惠爽。
Atlas是什么
2013年癌蓖,手淘航母戰(zhàn)略的制定,帶來了業(yè)務(wù)和開發(fā)人員的翻倍膨脹婚肆。從不到100人猛增四五倍租副,同時業(yè)務(wù)數(shù)量大增,整個客戶端的架構(gòu)和發(fā)版節(jié)奏受到極大挑戰(zhàn)较性,Atlas作為之前手淘客戶端的基礎(chǔ)框架用僧,進行了一次大的重構(gòu),形成了今天的Atlas赞咙。
Atlas是一個Android客戶端容器化框架责循,主要提供了組件化、動態(tài)性攀操、解耦化的支持院仿。支持工程師在工程編碼期、Apk運行期以及后續(xù)運維修復(fù)期的各種問題速和。
在工程期歹垫,實現(xiàn)工程獨立開發(fā),調(diào)試的功能颠放,工程模塊獨立排惨。

在運行期,實現(xiàn)完整的組件生命周期的映射碰凶,類隔離等機制暮芭。

在運維期鹿驼,提供快速增量的更新修復(fù)能力,快速升級谴麦。

Atlas是工程期和運行期共同起作用的框架蠢沿,它的特點是盡量將一些工作放到工程期,這樣來保證運行期的簡單匾效,穩(wěn)定舷蟀。
目前,Atlas在淘系A(chǔ)pp的應(yīng)用十分廣泛面哼,手淘自身超過60+業(yè)務(wù)組件野宜、20個協(xié)作團隊,以及百萬行級別代碼都在Atlas上運行魔策,其快速迭代能力讓應(yīng)用的發(fā)布周期從每月到每周再到隨時發(fā)布匈子,在過去半年里就發(fā)布了446次。另外Atlas本身非常輕量闯袒,只有90多個類虎敦,支持大小型App開發(fā),從大型的手淘到相對小型的阿里健康等都是用的這個框架政敢。其穩(wěn)定性也接受了考驗其徙,兼容Android 4.x以上系統(tǒng)版本。整體手淘的Crash率一直維持在萬分之五左右喷户,因為容器導(dǎo)致的crash占比小于百分之一唾那。
從這個意義上來說,Atlas首先要解決的問題是大規(guī)模團隊的協(xié)作問題褪尝,訴求包括并行開發(fā)闹获、快速迭代、工程解耦河哑,然后解決的問題是客戶端動態(tài)更新的問題避诽。手淘內(nèi)部思考的解決方案就是組件化。
Atlas組件化實現(xiàn)
組件化璃谨,業(yè)界稱為插件化茎用,不過這里Atlas的組件化和現(xiàn)在的插件化有一些不一樣的地方。組件化是需要去知道組件的功能睬罗,設(shè)計更規(guī)范轨功。


(手淘APK包目錄結(jié)構(gòu))
這是一個手機淘寶的APK包,第一層目錄上與標(biāo)準(zhǔn)的APK是完全一樣的容达,在APP會有很多的so文件古涧,如果解開來看的話,它的結(jié)構(gòu)類似于完整的APK花盐,但本身并不能獨立運行羡滑,它跟很多插件化的差別是在運行期菇爪,它是運行在整個容器里的,每一個組件都是獨立的Bundle柒昏。



從模塊來劃分凳宙,手淘APK可以分為兩層,上層是經(jīng)過拆分的業(yè)務(wù)Bundle职祷,掃碼氏涩、評價、詳情有梆,各個業(yè)務(wù)之間可以進行功能的調(diào)用是尖,可以通過路由調(diào)度到其他業(yè)務(wù)方。下層是共享的底層中間件泥耀,向業(yè)務(wù)方開放各種能力饺汹,如網(wǎng)絡(luò)庫、圖片庫等痰催,會在容器里進行統(tǒng)一地把控兜辞,這樣做的好處是包做到盡可能小,第二是性能佳夸溶。

這一塊是Atlas的整體設(shè)計逸吵,分為五層:
第一層我們稱之為Hack層,包括OS Hack toolkit & verifier蜘醋,這里我們對系統(tǒng)能力做一些擴展胁塞,然后做一些安全校驗咏尝。
第二層是Bundle Franework压语,就是我們的容器基礎(chǔ)框架,提供Bundle管理编检、加載胎食、生命周期、安全等一些最基本的能力允懂。

第三層是運行期管理層厕怜,包括清單,我們會把所有的Bundle和它們的能力列在一個清單上蕾总,在調(diào)用時方便查找粥航;另外是版本管理,會對所有Bundle的版本進行管理生百;再就是代理递雀,這里就是和業(yè)界一些插件化框架機制類似的地方,我們會代理系統(tǒng)的運行環(huán)境蚀浆,讓Bundle運行在我們的容器框架上缀程;然后還有調(diào)試和監(jiān)控工具搜吧,是為了方便工程期開發(fā)調(diào)試。
第四層是業(yè)務(wù)層了杨凑,這里我們向業(yè)務(wù)方暴露了一些接口滤奈,如框架生命周期、配置文件撩满、工具庫等等蜒程。
最上面一層是應(yīng)用接入層,就是我們的業(yè)務(wù)代碼了鹦牛。
所以Atlas作為一個框架提供了相對完整的能力搞糕,業(yè)務(wù)層的開發(fā)可以在框架生命周期的各個環(huán)節(jié)做一些自定義的動作,也可以自由的調(diào)用系統(tǒng)曼追、框架窍仰,乃至其它組件釋放的能力。
組件化技術(shù)細節(jié)
前面講的是容器層面的比較概要的東西礼殊,下面我們會講一些具體的細節(jié)驹吮。
關(guān)于Bundle的生命周期會提供細粒度的節(jié)點,比如下面是一個Bundle從加載到運行的周期:
startInstall:開始加載晶伦。這個時候框架會做一些拷貝文件碟狞、釋放lib、加載Bundle的事情婚陪;

Installed:加載完畢族沃。這時框架會注入資源路徑,創(chuàng)建class loader泌参;

resolved:解析完畢脆淹,框架會檢查組件配置是否合法,是否能被解析沽一;

active:運行組件盖溺,即開始運行組件Bundle;

started:運行成功铣缠。

組件化涉及到的第一個問題是Manifest處理烘嘱,一個是因為來源很多,有宿主Manifest蝗蛙、Aar Manifest以及組件Manifest蝇庭,另外不同組件的Manifest經(jīng)常發(fā)生變化,要求我們靈活地去處理捡硅。這里的做法是在工程期將所有的Manifest進行Merge操作哮内,這里需要注意的是Bundle的依賴單獨Merge,因為這里涉及到依賴仲裁的問題病曾。最后解析各個Bundle的Merge Manifest牍蜂,得到整包的BundleInfoList漾根,就是上面我們提到的Bundle信息清單。



第二個是類加載鲫竞,這里利用Delegate ClassLoader來動態(tài)加載組件的類辐怕。Delegate ClassLoader先查找宿主Bundle的PathClassLoader,然后根據(jù)前面的BundleList找到對應(yīng)的BundleClassLoader.



第三個是資源从绘,我們會用自己的DelegeteResources替換掉系統(tǒng)的resource寄疏,Bundle的資源會逐個在安裝的時候添加到AssertPath,由于添加Bundle的順序非固定僵井,不分區(qū)會導(dǎo)致資源查找錯亂陕截。
另外,Dalvik和ART上的資源查找過程順序是不一樣的批什,加上小米等系統(tǒng)會重寫自己的resources农曲,所以我們會適配不同的機型,往后追加AssetsPath或者往前追加驻债,系統(tǒng)AssetManager是個單例乳规,默認(rèn)往后追加,如果往前追加合呐,則需要重新創(chuàng)建AssetsManager對象暮的,同樣主dex動態(tài)部署的時候要達到替換原有resource的目的,必須保證插入順序與查找順序一致淌实。

還有需要注意的是冻辩,每次更新resourceTable的時候,必須保證apkresource拆祈,runtime的系統(tǒng)resource恨闪,例如webview,bundle resource都已經(jīng)添加成功缘屹,而且唯一凛剥,順序正確侠仇。
不同Bundle的資源可能發(fā)生命名沖突轻姿,我們是用了一種相對來說簡單的方法,將各自的Bundle分配成不同的ID逻炊,保證所有的業(yè)務(wù)資源不會產(chǎn)生沖突互亮,盡量將問題放到工程期解決。在很多代碼里余素,通過反射來調(diào)用整個資源豹休,在5.0以上的系統(tǒng)是沒有問題的,它只找第一個桨吊,對業(yè)務(wù)代碼而言威根,原來是怎么寫的凤巨,今天還是怎么去寫。
關(guān)于組件化性能這一部分洛搀,我們引入了按需加載敢茁,因為手淘APK有70多個Bundle,每個用戶真正用的時候只需要5或10個留美,所以不需要加載所有的Bundle彰檬。Bundle之間進行隔離,通過Android四大原生組件進行交互谎砾,這樣Bundle之間可以比較好的解耦逢倍。我們所有調(diào)用的入口都是基于BundleInfolist去做的,根據(jù)這個清單信息景图,得到組件所在Bundle较雕,如果需要加載,我們就進行install挚币、dexopt等操作郎笆。
另外,對于解決組件依賴問題忘晤,定義了兩種新的組件格式Awb(業(yè)務(wù)Bundle)和solib(so庫)宛蚓,前者與AAR一致,不過不添加本地lib设塔,在構(gòu)建的時候做依賴仲裁區(qū)分凄吏,后者是Native so庫的依賴。Awb其實就是AAR闰蛔,只是后綴修改了痕钢,如果你的包放在宿主Bundle就用AAR,如果是組件Bundle就用Awb序六。
對于業(yè)務(wù)Bundle的依賴任连,我們在構(gòu)建期會將宿主Bundle和業(yè)務(wù)Bundle及其依賴分別打包,然后按照最短路徑例诀、第一聲明原則進行樹狀仲裁随抠,得到每個Bundle需要的依賴,在打包的時候會將依賴庫放到各自的Bundle里去繁涂。



最后是APK構(gòu)建拱她,我們對它做了比較大的調(diào)整。上面的圖中扔罪,其實左邊這一部分是一個標(biāo)準(zhǔn)的APK的構(gòu)建過程秉沼,包括處理,編譯,到簽名的過程唬复。我們這個不同的地方是多了Awb需要特殊處理矗积,其中Awb的資源根據(jù)宿主的resource.ap_和包內(nèi)資源構(gòu)建,R文件由Bundle R資源和宿主R資源合并而來敞咧,然后我們對Aapt進行了修改漠魏,對每個awb分配不同的packageId,然后進行統(tǒng)一混淆妄均,生產(chǎn)各個AWB的Dex柱锹,打包為APK,簽名之后復(fù)制到libs丰包,改名為so文件禁熏,然后合并到taobao APK. 這就是我們組件化的整個過程。
Atlas動態(tài)化
在一個容器框架內(nèi)邑彪,組件化和動態(tài)化是相輔相成的瞧毙,組件只是解決了解耦的問題,但我們?nèi)绻胍S時發(fā)包寄症,就必須讓容器框架具備動態(tài)化能力宙彪。我們在完成了Atlas的組件化之后,做了動態(tài)化的支持有巧。動態(tài)化的好處一個是包的大小縮減释漆,我們可以將一些包在運行后下載到應(yīng)用中,另一個是具備動態(tài)發(fā)版和修復(fù)能力篮迎。
增量動態(tài)化方案
Atlas提供了動態(tài)部署的能力男图,主要目標(biāo)是動態(tài)業(yè)務(wù)發(fā)布,以及問題修復(fù)甜橱。它基于手淘自研差量算法逊笆,主Bundle基于ClassLoader機制,業(yè)務(wù)Bundle基于差量merge岂傲,支持全業(yè)務(wù)類型难裆。
另外,Atlas也支持Andfix作為插件使用镊掖,目標(biāo)是快速故障修復(fù)乃戈,它的原理基于Native hook,主要做方法的修改堰乔,在實際中可以兩個一起用偏化。在工程構(gòu)建期適配之后脐恩,可以做到一套代碼兩套方案通用镐侯。

自研動態(tài)部署功能實現(xiàn)原理,首先,對于Dex Patch的生成苟翻,我們通過修改Dex的字節(jié)碼實現(xiàn)韵卤,將Dex文件轉(zhuǎn)為Smali,對其中的ClassDef和ClassDataMethod結(jié)構(gòu)體進行分析崇猫,可以實現(xiàn)刪除沈条、新增惭蟋、修改類盅弛,然后通過Diff處理得到差量文件,再通過Merge處理即生成補丁薯鳍。
其次是整個資源Patch的生成涕烧,分為兩塊月而,一個是業(yè)務(wù)Bundle,本來是一個不斷加載的過程议纯,它實現(xiàn)起來會比較簡單父款,通過Md5 diff/BSDiff即可得到。對于主Bundle瞻凤,因為安卓本身有一個限制憨攒,所有的資源必須得在base包里,新增一個資源是不生效的阀参。所以一個做法是在打包的時候預(yù)留很多空資源肝集。另外更新已有的資源則通過資源覆蓋來完成。
最后蛛壳,如果新加業(yè)務(wù)的話包晰,會新加Activity,我們的做法首先在Manifest預(yù)埋一個StubActivity炕吸,然后在Instrumentation.execStartActivity()階段進行替換伐憾,同時配合Intent setFlag模擬Activity launch mode并繼續(xù)startActivity,接著System_server進程進行處理赫模,更新ActivityStack树肃,創(chuàng)建binder,并通知ActivityThread進行實例創(chuàng)建瀑罗,最后我們在ActivityThread的handler里面進行攔截胸嘴,更新ActivityInfo等信息,創(chuàng)建目標(biāo)Activity斩祭。
另外在工程實踐上劣像,因為補丁的生成會涉及到Dex和資源的基線,我們會在部署的時候摧玫,每次發(fā)布APK包同步發(fā)布AP(基線包)到Maven耳奕,AP基線包里是所有影響基線的文件,第一是安卓APK,第二是Mapping.txt屋群,最后是Dependency.txt闸婴,這樣的話整個構(gòu)建的速度會非常的快。
所以我們這種方式芍躏,版本的升級是不同的方式邪乍。比如今天手淘的詳情要更新,會發(fā)布版本对竣,這個版本可能不是到應(yīng)用市場的版本庇楞,而是一個Patch包。業(yè)務(wù)版本的動態(tài)部署否纬,我們是同步的姐刁,5.3.0到5.3.1到5.3.2,這樣一個好處是只要容器版本沒有升級烦味,只要有需求聂使,patch就可以一直升級谬俄,而且是無感知的差量升級。
周邊優(yōu)化點
最后來講講我們的周邊優(yōu)化點,為什么到今天才說要開源,做的過程當(dāng)中還是遇到了不少問題。
第一點是Bundle的重復(fù)資源合并。因為我們發(fā)現(xiàn),因為宿主問題占锯,必然而然會出現(xiàn)沖突的問題歪脏,包括圖片資源,我們會放到整個宿主類目中去。
第二是Bundle的依賴校驗,以前是代碼的話稽穆,是編譯過的,但因為今天是二進制,這個問題會遺留到現(xiàn)場去吓蘑,所以會看看API是否會影響B(tài)undle。
第三是類庫“瘦身”坟冲,因為手淘依賴的各種中間件類庫太多了磨镶,導(dǎo)致手淘本身很臃腫,方法數(shù)很大健提;所以打包的時候?qū)︻悗煊幸粋€裁剪的過程琳猫,優(yōu)化方法數(shù)。
第四是依賴導(dǎo)致的私痹,依賴查詢庫脐嫂。
第五是做Dex File等统刮,進行混淆Mapping。
最后是開源準(zhǔn)備中账千,我們在工程期侥蒙、運行期都會去做開源,并且將機制通過云服務(wù)的方式提供出來匀奏,阿里百川會提供Atlas的研發(fā)支撐能力鞭衩,包括快捷的生成,發(fā)布娃善,回滾论衍,監(jiān)控等能力。

轉(zhuǎn)發(fā)用于學(xué)習(xí)交流,如冒犯,請聯(lián)系刪除聚磺。

原文連接:http://mp.weixin.qq.com/s?__biz=MzA3ODg4MDk0Ng==&mid=2651112809&idx=1&sn=8d45d8960acde6128b121fb10a6d7bb7

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末坯台,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子瘫寝,更是在濱河造成了極大的恐慌蜒蕾,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件焕阿,死亡現(xiàn)場離奇詭異咪啡,居然都是意外死亡,警方通過查閱死者的電腦和手機捣鲸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門瑟匆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人栽惶,你說我怎么就攤上這事愁溜。” “怎么了外厂?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵冕象,是天一觀的道長。 經(jīng)常有香客問我汁蝶,道長渐扮,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任掖棉,我火速辦了婚禮墓律,結(jié)果婚禮上幔亥,老公的妹妹穿的比我還像新娘帕棉。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著拔稳,像睡著了一般巴比。 火紅的嫁衣襯著肌膚如雪轻绞。 梳的紋絲不亂的頭發(fā)上唧龄,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天懒叛,我揣著相機與錄音胖烛,去河邊找鬼。 笑死趟畏,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的哗咆。 我是一名探鬼主播,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起响迂,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年瞄摊,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片递瑰。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡抖部,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出议惰,到底是詐尸還是另有隱情慎颗,我是刑警寧澤,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布换淆,位于F島的核電站哗总,受9級特大地震影響几颜,放射性物質(zhì)發(fā)生泄漏倍试。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一蛋哭、第九天 我趴在偏房一處隱蔽的房頂上張望县习。 院中可真熱鬧,春花似錦谆趾、人聲如沸躁愿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽彤钟。三九已至,卻和暖如春跷叉,著一層夾襖步出監(jiān)牢的瞬間逸雹,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工云挟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留梆砸,地道東北人。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓园欣,卻偏偏與公主長得像帖世,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子沸枯,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,047評論 2 355

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,170評論 25 707
  • VirtualAPK插件框架簡單使用阿里Atlas組件框架使用 最近一段時間在研究插件化和組件化實現(xiàn)方案日矫,今天也算...
    閑庭閱讀 11,479評論 1 20
  • 榆林事件引來一片熱議赂弓,看來生男生女都是愁啊[捂臉]不過中國的法律夠奇芭的,明明是成年人哪轿,意識清晰拣展,其他手術(shù)...
    芊雪姑娘閱讀 248評論 0 2
  • 民間傳聞,禿鷲喜歡吃死人缔逛,尤其是死嬰备埃,1988年的一個村莊,發(fā)生了一件禿鷲吃人案褐奴,接下來就讓我們回顧案情按脚,爺爺,奶...
    天堂沒有鉛筆閱讀 3,227評論 2 0
  • 情景:zara買衣服敦冬。 W:這男裝毛衣辅搬,左面奶奶款,中間爺爺款脖旱,右面…… L:(拿起后)孫子款~~~
    洗粉小能手閱讀 116評論 0 0