阿里資深工程師分享支付寶熱補丁技術—— AndFix原理


  本文由嵌入式企鵝圈原創團隊成員、阿里資深工程師Hao分享。

  上次我們介紹了用dexposed方案實施熱補丁的原理,它本質上就是hook要修改的函數,這樣一來在正式版本發布時就不能直接拿熱補丁的代碼集成進去了,因為熱補丁是按hook的思路,並且按照實現XC_MethodReplacement類的方式寫的,正式的補丁還需要重新包裝一邊。更重要的是dexposed對art的支持並不好,大大限制了它的使用范圍。

   今天我們介紹的是AndFix方案:https://github.com/alibaba/AndFix。它按照正常修bug的思路寫補丁代碼,正式發布時直接集成補丁代碼即可,適用范圍廣,在dalvik和Art上都可以使用。它分為兩部分,一是生成補丁的工具,二是客戶端加載補丁的SDK。支付寶錢包使用的就是這個方案。

   我們基於線上的最新版本修完bug后,會構建出一個apk,用AndFix提供的diff工具,找出已發布的線上的apk和修復后的apk中classes.dex之間的“差異”,也就是修復bug后發生變化的方法,再用工具生成一個apatch文件,跟apk一樣,它也是個壓縮包,里面包含CERT.RSA、CERT.SF、MANIFEST.MF、diff.dex和PATCH.MF這幾個文件。客戶端從服務端拉取該apatch文件后,解析diff.dex,找到要加載的類和要替換的方法methodReplaced,最后用hook的方式替換掉,這樣就完成了在線修復的工作。本篇我們只介紹客戶端加載補丁的SDK的主要原理,不介紹生成補丁的工具,照例還是先不管ART,只介紹dalvik下是怎樣運行的。 

一、解析補丁的配置文件PATCH.MF

1.首先PatchManager的addPatch方法可以用來添加一個補丁,並執行替換操作。 

 

  可見,用生成的補丁文件File來構造一個Patch類,然后再執行loadPatch來加載補丁。 

  因為補丁文件apatch是一個jar包,所以用JarFile、Manifest等類來解析META-INF/PATCH.MF配置文件,找到要替換的類名,接下來loadPatch調用AndFixManager的fix方法,傳入補丁的File對象、當前Context的classLoader和從PATCH.MF解析出的要替換的補丁類名。 

  fix方法中用傳入的classLoader構造一個自定義的pathClassLoader,它的findClass方法用來找到要替換的類的Class對象。


  這里的dexFile直接由loadDex得到,這樣補丁文件中的dex文件就已經加載到應用中了。


2. 接下來依次把要修復的類加載進來,並調用fixClass方法開始替換工作。

 

 

二、找到要替換的類的方法,並把類成員的屬性改為public 

  這里巧用了java的Annotation原理幫助我們在apk中找到要修復的方法。在apatch中補丁方法寫了注釋annotation,clazz和method表示要修復的類和方法。在AndFixManager的fixClass中會根據這個Annotation找出要修復的Method對象。遍歷類的全部Method,如果發現有MethodReplace的注釋就開始准備替換工作。method是原apk(有bug)的方法,meth是新修復的方法,接着調用replaceMethod。

replaceMethod里先后調用了initTargetClass和addReplaceMethod,注意這里的classLoader不是上面提到的pathClassLoader而是原apk中要修復的類的classLoader。這樣原來有bug的class和補丁中的class都已經被加載進來了。

  initTargetClass中主要調用native的方法setFieldFlag把class中的所有成員都設為public, 

  addReplaceMethod同樣也是調用native的方法replaceMethod。 

三、替換原來的Method

  替換原來方法的處理方式我們看起來會有點熟悉,一般的java hook差不多都是這樣的套路,在jni中找到要替換方法的Method對象,修改它的一些屬性,讓它指向新方法的Method對象。

 

  這里dvmDecodeIndirectRef_fnPtr和dvmThreadSelf_fnPtr都是在AndFix初始化時賦好值的函數指針,用來調dvm的dvmDecodeIndirectRef和dvmThreadSelf函數。

  這里apilevel > 10的意思是,在apilevel 10以前dvm是用c語言實現的,以后是用C++實現的。

以上所有的過程是在應用MainApplication的onCreate中被調用,所以當應用重啟后,原方法和補丁方法都被加載到內存中,並完成了替換,在后面的運行中就會執行補丁中的方法了。 

  AndFix的優點是像正常修復bug那樣來生成補丁包,但可以看出無論是dexposed還是AndFix,都利用了java hook的技術來替換要修復的方法,這就需要我們理解dalvik虛擬機加載、運行java方法的機制,並要掌握libdvm中一些關鍵的數據結構和函數的使用。

  百分百原創,每周兩篇,阿里、魅族、nvidia、龍芯、炬力、拓爾思等頂級企業資深工程師分享----嵌入式、Linux、物聯網、GPU、Android、自動駕駛等技術,歡迎掃碼關注微信公眾號:嵌入式企鵝圈,實時推送原創文章!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM