dex優化對Arouter查找路徑的影響

1、前言

疑問:dex文件是什麼?dex文件優化又是什麼?java

dex文件優化會給項目帶來什麼問題,怎麼解決這些問題?android

1.1 APK的編譯和打包流程

一、經過aapt打包資源文件res,對應生成R.java、resources.arsc和res文件(二進制&非二進制保持原來的代碼)框架

二、處理aidl文件,生成java接口文件(沒有aidl 則忽略)工具

三、經過java compile編譯R.java、 java接口文件,生成對應.class文件(java compiler)gradle

四、運用dex命令,將.class文件和第三方sdk庫中的.class文件轉換成classes.dex文件優化

五、經過apkbuilder將aapt生成的CompiledResources和其餘資源文件以及classes.dex文件打包生成apkui

六、一樣的,可使用Jarsigner工具,對上面的apk進行debug或者release簽名google

apk的編譯和打包流程圖以下:spa

圖片

實際項目開發中,五、6兩個步驟,能夠藉助jenkins平臺直接生成release包便可知足需求。.net

1.2 dex文件的應用場景

再來看看dex文件經常使用的場景,比較流行的有:APK 的瘦身、熱修復、插件化、應用加固、Android 逆向工程、64 K 方法數限制。

拿方法數限制舉例,在上面的第4步,將class文件轉換成dex文件,默認只會生成一個dex文件,單個dex文件中的方法數不能超過65536,否則編譯會報錯,可是咱們在開發App時確定會集成一堆庫,方法數通常都是超過65536的,解決這個問題的辦法就是:一個dex裝不下,用多個dex來裝,gradle增長一行配置:multiDexEnabled true。

dex文件的應用場景網上介紹的不少,本文不作介紹。而是對項目中實際遇到的問題進行剖析,從而對dex優化有進一步的理解。

2、dex到vdex、odex

2.1 ART預優化

ART(Android runtime)是什麼,它是虛擬機,運營java代碼、APP用的。參考Android發展史,Android 5.0把ART做爲默認的虛擬機,而不是Android4.4及以前使用的DVM(Dalvik VM)了。

回顧一下DVM和ART和Android的關係,咱們先來了解運行Java的幾種虛擬機的工做機制:(1)JVM:JVM虛擬機運行的是java字節碼。Java文件到JVM的過程是:java -> java bytecode(class) -> java bytecode(jar)

DVM:DVM虛擬機解析執行的dex字節碼。Java文件到DVM的過程是:java -> java bytecode(class) -> dalvik bytecode(dex)

ART:ART虛擬機執行本地機器碼。Java文件到ART的過程是:java -> java bytecode(class) -> dalvik bytecode(dex) -> optimized android runtime machine code(oat)

能夠看到,DVM到ART的演變,其實是java文件到虛擬機的執行代碼的過渡,相對而言,ART多了oat的過程,ART使用AOT(Ahead-Of-Time)編譯,在應用第一次安裝的時候,字節碼預編譯成機器碼存在本地,DVM是使用JIT(Just-In-Time)編譯,在應用每次運行的時候,字節碼都須要經過編譯器即時轉換爲機器碼才能繼續執行。ART相對於DVM,省去了每次解析字節碼的過程,因此運行時佔用的內存會減小,提高應用的運行效率。

2.2 ART的運行方式

ART在Android5.0時代,號稱使用AOT便可讓系統運行在512M的機器上。從 Android 7.0(簡稱 N)開始,ART結合 AOT、即時 (JIT) 編譯和配置文件引導型編譯。

這幾種模式能夠組合配置,以谷歌的Pixel 設備舉例,配置瞭如下編譯流程:

1)最初安裝應用時不進行任何 AOT 編譯。應用前幾回運行時,系統會對其進行解譯,並對常常執行的方法進行 JIT 編譯。

2)當設備閒置和充電時,編譯守護進程會運行,以便根據在應用前幾回運行期間生成的配置文件對經常使用代碼進行 AOT 編譯。

下一次從新啓動應用時將會使用配置文件引導型代碼,並避免在運行時對已經編譯過的方法進行 JIT 編譯。在應用後續運行期間進行了 JIT 編譯的方法將會被添加到配置文件中,而後編譯守護進程將會對這些方法進行 AOT 編譯。

ART 包括一個編譯器(dex2oat 工具)和一個爲啓動 Zygote 而加載的運行時 (libart.so)。dex2oat 工具接受一個 APK 文件,並生成一個或多個編譯文件,而後運行時將會加載這些文件。文件的個數、擴展名和名稱會因版本而異,但在 Android O 版本中,將會生成如下文件:

vdex:其中包含 APK 的未壓縮 DEX 代碼,另外還有一些旨在加快驗證速度的元數據。

odex:其中包含 APK 中通過 AOT 編譯的方法代碼。

art (optional):其中包含 APK 中列出的某些字符串和類的 ART 內部表示,用於加快應用啓動速度。

2.3 vdex、odex的做用

解壓一個APK(以廠商的系統應用包舉例)的包,能夠看到下面的結構,不含有任何dex文件

圖片

再看下這個應用在手機中的目錄結構,vdex、odex文件包含apk的全部代碼,正常也會包含classes.dex文件。因爲vdex、odex是機器碼,沒辦法直接轉成能夠查看的二級制碼查看(也多是我使用的工具不對)。

2.4 vdex、odex與classes.dex關係

多是系統編譯的bug,也多是生成了ART文件以後,對odex、vdex文件作了二次處理,現象是這樣的,嘗試獲取odex中的dex文件,提示不含有dex文件。

圖片

爲了再次確認odex裏面是否真的含有dex文件,使用010Editor再次確認,能夠看到recent Files下面仍然是沒有dex文件的。

圖片

嘗試獲取vdex中的dex文件,也是沒法獲取的。

圖片

因此說,odex(或者vdex)中含有classes.dex的說法是不正確的。

3、Arouter是什麼

阿里的一個路由組件,功能不少,我這邊的實際使用場景是進行頁面跳轉。具體功能能夠參考阿里峯會上對arouter的介紹

借鑑峯會中提到的一點做爲鋪墊,也是咱們下面將要講述的一點。「最後想分享的就是ARouter的將來開發計劃。將來ARouter會支持插件化而且支持生成映射關係文檔,由於插件化是如今不少大型APP中會使用的技術方案,不少的Dex和功能是動態地下發到APP中的,而在這種狀況下,是沒法找到全部的Dex文件的,也就是對於沒有加載過的Dex而言,裏面的映射關係是跳轉不過去的,因此一旦Dex文件位置發生變更,常規的方案是沒法找到Dex的,也不能實現映射文件初始化,這一部分會在後面的版本中進行支持」。

阿里能夠識別的arouter路徑以下:

圖片

換句話說,arouter可能由於dex文件的位置變化或者路徑變化,而沒法找到。

4、踩坑

4.1 現象

2.4中提到了odex文件中不含有dex,而arouter查找路徑遵循分組按需加載的規則,歸結到底,實際上就是對class文件的查找,以下圖:

圖片

而class文件的信息記錄在dex文件中,因此出現了異常,使用arouter進行頁面跳轉的時候,出現classNotFound exception。

4.2 解決方案

想要找到解決方案,就要知道怎麼樣讓odex對arouter路徑不產生影響,這方面,可能在沒有相關經驗的時候,很難找到解決方案,只能一點點查找。經過搜索ART的工做原理,找到文章《配置ART》,其中文章提到:

圖片

也就是說經過配置LOCAL\_DEX\_PREOPT的屬性,能夠防止odex優化,因而找到Android.mk中設置該屬性的地方進行設置LOCAL\_DEX\_PREOPT := nostripping。

圖片

既在編譯的時候作dex優化(生成odex文件),又不從apk裏剝離dex。因而有了下面的apk生成以後的路徑對比,再看下dex不被剝離的路徑,下面含有了classes.dex文件。

圖片

使用jadx打開這個classes.dex文件,發現arouter的路徑文件就在這裏,因此arouter的跳轉正常了,異常再也不出現。

圖片

5、總結

odex優化這種系統作的事情,每每會出現一些意想不到的結果,若是你負責廠商的應用,常常須要內置項目,這時候要注意了,當你的應用中含有第三方框架的時候,要注意路徑、資源的引用都是沒問題的,雖然正常狀況下,odex文件不會對你的路徑產生干擾,可是也不免odex出現失誤,由於對於odex來講,裏面的資源無需保存,生成art文件可以運行便可。合理使用art的配置,能夠幫助解決不少問題。

做者:vivo互聯網客戶端團隊-Xu jie
相關文章
相關標籤/搜索