久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

安卓App熱補丁動態修復技術是什么

152次閱讀
沒有評論

共計 3135 個字符,預計需要花費 8 分鐘才能閱讀完成。

這篇文章將為大家詳細講解有關安卓 App 熱補丁動態修復技術是什么,文章內容質量較高,因此丸趣 TV 小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。

1. 背景

當一個 App 發布之后,突然發現了一個嚴重 bug 需要進行緊急修復,這時候公司各方就會忙得焦頭爛額:重新打包 App、測試、向各個應用市場和渠道換包、提示用戶升級、用戶下載、覆蓋安裝。有時候僅僅是為了修改了一行代碼,也要付出巨大的成本進行換包和重新發布。
這時候就提出一個問題:有沒有辦法以補丁的方式動態修復緊急 Bug,不再需要重新發布 App,不再需要用戶重新下載,覆蓋安裝?
雖然 Android 系統并沒有提供這個技術,但是很幸運的告訴大家,答案是:可以,我們 QQ 空間提出了熱補丁動態修復技術來解決以上這些問題。

2. 實際案例

空間 Android 獨立版 5.2 發布后,收到用戶反饋,結合版無法跳轉到獨立版的訪客界面,每天都較大的反饋。在以前只能緊急換包,重新發布。成本非常高,也影響用戶的口碑。最終決定使用熱補丁動態修復技術,向用戶下發 Patch,在用戶無感知的情況下,修復了外網問題,取得非常好的效果。

3. 解決方案

該方案基于的是 android dex 分包方案的,關于 dex 分包方案,網上有幾篇解釋了,所以這里就不再贅述,具體可以看這里
簡單的概括一下,就是把多個 dex 文件塞入到 app 的 classloader 之中,但是 android dex 拆包方案中的類是沒有重復的,如果 classes.dex 和 classes1.dex 中有重復的類,當用到這個重復的類的時候,系統會選擇哪個類進行加載呢?
讓我們來看看類加載的代碼:

一個 ClassLoader 可以包含多個 dex 文件,每個 dex 文件是一個 Element,多個 dex 文件排列成一個有序的數組 dexElements,當找類的時候,會按順序遍歷 dex 文件,然后從當前遍歷的 dex 文件中找類,如果找類則返回,如果找不到從下一個 dex 文件繼續查找。
理論上,如果在不同的 dex 中有相同的類存在,那么會優先選擇排在前面的 dex 文件的類,如下圖:

在此基礎上,我們構想了熱補丁的方案,把有問題的類打包到一個 dex(patch.dex)中去,然后把這個 dex 插入到 Elements 的最前面,如下圖:

好,該方案基于第二個拆分 dex 的方案,方案實現如果懂拆分 dex 的原理的話,大家應該很快就會實現該方案,如果沒有拆分 dex 的項目的話,可以參考一下谷歌的 multidex 方案實現。然后在插入數組的時候,把補丁包插入到最前面去。
好,看似問題很簡單,輕松的搞定了,讓我們來試驗一下,修改某個類,然后打包成 dex,插入到 classloader,當加載類的時候出現了(本例中是 QzoneActivityManager 要被替換):

為什么會出現以上問題呢?
從 log 的意思上來講,ModuleManager 引用了 QzoneActivityManager,但是發現這這兩個類所在的 dex 不在一起,其中:

ModuleManager 在 classes.dex 中

QzoneActivityManager 在 patch.dex 中
結果發生了錯誤。
這里有個問題, 拆分 dex 的很多類都不是在同一個 dex 內的, 怎么沒有問題?

讓我們搜索一下拋出錯誤的代碼所在,嘿咻嘿咻,找到了一下代碼:

從代碼上來看,如果兩個相關聯的類在不同的 dex 中就會報錯,但是拆分 dex 沒有報錯這是為什么,原來這個校驗的前提是:

如果引用者(也就是 ModuleManager)這個類被打上了 CLASS_ISPREVERIFIED 標志,那么就會進行 dex 的校驗。那么這個標志是什么時候被打上去的?讓我們在繼續搜索一下代碼,嘿咻嘿咻~,在 DexPrepare.cpp 找到了一下代碼:

這段代碼是 dex 轉化成 odex(dexopt)的代碼中的一段,我們知道當一個 apk 在安裝的時候,apk 中的 classes.dex 會被虛擬機 (dexopt) 優化成 odex 文件,然后才會拿去執行。
虛擬機在啟動的時候,會有許多的啟動參數,其中一項就是 verify 選項,當 verify 選項被打開的時候,上面 doVerify 變量為 true,那么就會執行 dvmVerifyClass 進行類的校驗,如果 dvmVerifyClass 校驗類成功,那么這個類會被打上 CLASS_ISPREVERIFIED 的標志,那么具體的校驗過程是什么樣子的呢?
此代碼在 DexVerify.cpp 中,如下:

驗證 clazz- directMethods 方法,directMethods 包含了以下方法:

static 方法

private 方法

構造函數

clazz- virtualMethods

虛函數 =override 方法?

概括一下就是如果以上方法中直接引用到的類(第一層級關系,不會進行遞歸搜索)和 clazz 都在同一個 dex 中的話,那么這個類就會被打上 CLASS_ISPREVERIFIED:

所以為了實現補丁方案,所以必須從這些方法中入手,防止類被打上 CLASS_ISPREVERIFIED 標志。
最終空間的方案是往所有類的構造函數里面插入了一段代碼,代碼如下:
if (ClassVerifier.PREVENT_VERIFY) {System.out.println(AntilazyLoad.class); }

其中 AntilazyLoad 類會被打包成單獨的 hack.dex,這樣當安裝 apk 的時候,classes.dex 內的類都會引用一個在不相同 dex 中的 AntilazyLoad 類,這樣就防止了類被打上 CLASS_ISPREVERIFIED 的標志了,只要沒被打上這個標志的類都可以進行打補丁操作。
然后在應用啟動的時候加載進來.AntilazyLoad 類所在的 dex 包必須被先加載進來, 不然 AntilazyLoad 類會被標記為不存在,即使后續加載了 hack.dex 包,那么他也是不存在的,這樣屏幕就會出現茫茫多的類 AntilazyLoad 找不到的 log。
所以 Application 作為應用的入口不能插入這段代碼。(因為載入 hack.dex 的代碼是在 Application 中 onCreate 中執行的,如果在 Application 的構造函數里面插入了這段代碼,那么就是在 hack.dex 加載之前就使用該類,該類一次找不到,會被永遠的打上找不到的標志)
其中:

之所以選擇構造函數是因為他不增加方法數,一個類即使沒有顯式的構造函數,也會有一個隱式的默認構造函數。
空間使用的是在字節碼插入代碼, 而不是源代碼插入,使用的是 javaassist 庫來進行字節碼插入的。
隱患:
虛擬機在安裝期間為類打上 CLASS_ISPREVERIFIED 標志是為了提高性能的,我們強制防止類被打上標志是否會影響性能?這里我們會做一下更加詳細的性能測試.但是在大項目中拆分 dex 的問題已經比較嚴重,很多類都沒有被打上這個標志。
如何打包補丁包:

空間在正式版本發布的時候,會生成一份緩存文件,里面記錄了所有 class 文件的 md5,還有一份 mapping 混淆文件。

在后續的版本中使用 -applymapping 選項,應用正式版本的 mapping 文件,然后計算編譯完成后的 class 文件的 md5 和正式版本進行比較,把不相同的 class 文件打包成補丁包。
備注: 該方案現在也應用到我們的編譯過程當中, 編譯不需要重新打包 dex, 只需要把修改過的類的 class 文件打包成 patch dex, 然后放到 sdcard 下, 那么就會讓改變的代碼生效。

關于安卓 App 熱補丁動態修復技術是什么就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2023-08-03發表,共計3135字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 延长县| 景洪市| 桐乡市| 新津县| 玉山县| 卢氏县| 阿瓦提县| 景东| 浏阳市| 龙井市| 临洮县| 赤水市| 永清县| 崇左市| 河曲县| 鄂托克旗| 潜山县| 武夷山市| 荥经县| 临泉县| 延庆县| 临洮县| 永州市| 靖安县| 湛江市| 乌鲁木齐市| 正镶白旗| 元江| 开江县| 开平市| 增城市| 广南县| 老河口市| 庆云县| 新泰市| 新野县| 赣榆县| 安福县| 青铜峡市| 滨海县| 丰都县|