1. 程式人生 > >關於Android APP線上熱修復bug方案的調研(一)(AndFix)

關於Android APP線上熱修復bug方案的調研(一)(AndFix)

調研背景:

     App釋出出去後,如果發現有緊急或重要bug如何進行修復呢?

     重新發布一版APK?但這樣代價太大....

      那麼有沒有一種方案能夠不用更新整個APK,而只把伺服器上的很小的補丁檔案下載下來進行修復bug呢?

      本文的調研也正是為了解決該問題。

幾種解決方案對比:

      下面是找到的3款比較火的開源解決方案,分別都是利用不同原理實現的:

名稱

優點

缺點

適用場景

實現原理與下載

AndFix

1.Mexdex方案相比,效能要好些。(Multi Dex需要修改所有classclass_ispreverified

標誌位,導致執行時效能有所損失)


2.
支援ARTDalvik

3.
支援6.0

1.跳過了類初始化,對於靜態或者建構函式或者class.forname()的處理可能會有問題

線上修復bug

Nuwa

(HotFix/DroidFix)

1.相容性比AndFix(Multi dex方案,沒有static的問題)

2.支援ARTDalvik

3.支援6.0

 1.編譯完成java程式碼後,需要遍歷修改class檔案,插入程式碼,防止class被打上class_ispreverified標誌,這會導致執行效能降低

線上修復bug

 結合我的目標,目標鎖定在第2個與第3個。

AndFix的操作使用】

選擇第二個AndFix來進行研究:

第一步:模擬釋出APK:

使用自帶的sample中的列子,修了下onCreate()中的程式碼,如下:


安裝執行bug.apk,如預期輸出如下Log:

第二步:現在App釋出出去後有Bug啦,我們要改變onCreate()的輸出,趕緊開始製作patch.....

修改輸出程式碼為如下:


編譯出fix後的APK,這時需要使用AndFix/tools/下面的apkpatch這個工具來製作patch(補丁)檔案。

工具所在目錄:


工具使用說明:

ApkPatch v1.0.3 - a tool for build/merge Android Patch file (.apatch).
Copyright 2015 supern lee <
[email protected]
> usage: apkpatch -f <new> -t <old> -o <output> -k <keystore> -p <***> -a <alias> -e <***> -a,--alias <alias> alias. -e,--epassword <***> entry password. -f,--from <loc> new Apk file path. -k,--keystore <loc> keystore path. -n,--name <name> patch name. -o,--out <dir> output dir. -p,--kpassword <***> keystore password. -t,--to <loc> old Apk file path. usage: apkpatch -m <apatch_path...> -k <keystore> -p <***> -a <alias> -e <***> -a,--alias <alias> alias. -e,--epassword <***> entry password. -k,--keystore <loc> keystore path. -m,--merge <loc...> path of .apatch files. -n,--name <name> patch name. -o,--out <dir> output dir. -p,--kpassword <***> keystore password.

下面就開始使用這個命令來製作patch檔案:
執行如下命令:
apkpatch.sh -f fixed.apk -t bug.apk -o out -k sig -p 123123 -a test_sig -e 123123

命令的輸出:
add modified Method:V  onCreate(Landroid/os/Bundle;)  in Class:Lcom/euler/andfix/MainActivity;


第三步:到此補丁檔案製作好了,就可以通過網路等渠道推送到手機上。

檢視out目錄,一共有3個,會在後面進行解釋:


這裡的.patch檔案就是我們需要的,把它push到手機:


重起剛才的APP,觀看Log輸出時否改變了:


^_^,補丁成功了,而且這個檔案也才3KB多點哦,非常適合線上修復bug~~~~

-rw-rw-r-- 1 yanchen yanchen 3468 12月 15 18:32 out/fixed-07d99a18833f092518fbb041c793e53b.apatch

AndFix的原始碼分析

============================================================================================================================

Patch的製作流程現在知道了,下一步就準備進入Code層面的分析,探究它的內部實現原理。

============================================================================================================================

首先來看Patch製作原理:

製作patch會用到apkpatch這個工具,而它會呼叫apkpatch-1.0.3.jar這個檔案。反編譯這個jar包,發現在製作patch時,它會進入ApkPatch的doPatch()這個函式完成的。

進入doPatch函式看看:


這個函式邏輯挺清晰的,一共就這4個步驟。

第一步是diff,它會比對兩個APK的差別,來看看它的程式碼是如何實現的:


這個函式會提取fixed.apk與bug.apk中的classes.dex檔案,然後通過2個for迴圈,來對比每個class檔案中的欄位與函式是否完全一致。

那麼欄位和函式又是如何對比的呢?

我們來看看compareMethod()函式內部實現:


原來對比函式時會看兩個是否有函式實現,有的話就會看兩個函式的函式體是否一致,程式碼如下:

如果不一致就會新增到一個叫info的HashSet變數中。

而比對欄位主要看欄位的初始值是否一樣,程式碼如下:


總結:

通過上面的步驟就比對出了兩個APK中的classes.dex中差別,並且將有差別的檔案儲存在了info變數中。

接下來進入第二步,開始進行buildCode(),這步的目的是將info中儲存的檔案寫到.smali檔案中,然後再打包成一個dex檔案。

比如下面的是我的demo產生的smali檔案:



在生成的smali函式中,它會新增一個自定義的Anotation,叫MethodReplace


到此,第二個步驟也就完成了,它一共產生2個檔案:

接下來進入第三個步驟,呼叫build()函式,這步會將上一步產生的dex檔案寫入到一個jar檔案,並進行簽名,程式碼如下:

PatchBuilder的程式碼如下:

所以第三步完成後,會產生一個叫作diff.apatch的jar檔案。

接下來進入最後一步,呼叫release()函式,也就是通過它產生最終的patch檔案。

看看release()中都做了些什麼事情:

主要是將第三步生成的diff.apatch檔案重新命名為name-md5-.patch格式的檔案

到此,patch的製作原理也就告一段落了,主要就是提取兩個APK中的classes.dex,對比他們中的class檔案是否有區別,將有區別的提取出來打包到.apatch檔案中。

最終的產物如下:

============================================================================================================================

以上是Patch的製作流程分析,下一下我們再來看看客戶端是如何將這個patch檔案打入自己的APK中的。

============================================================================================================================

要使用這套框架,客戶端只需在Application的onCreate()中加入如下的程式碼:

那我們就來看看這幾行程式碼到底會做什麼事情。

init()函式主要工作時載入files/apatch/目錄下的.apatch檔案,程式碼如下:

initPatchs()程式碼如下:

它讀取mPathDir目錄下的所有.patch檔案,並將起新增到一個叫mPatchs的HashSet變數中。

這是mPatchDir的初始值:

看來這個函式的目的就是在啟動的時候,讀取所有本地的patch檔案。

讀取完畢後呼叫loadPatch()來進行執行時的APK修復,程式碼如下:

fix()函式的程式碼如下:

它會載入.apatch檔案中class,然後再呼叫fixClass(),繼續往下看:


會讀取自定義的Anotation MethodReplace,通過它獲取到class名字與method名字,進行替換。

在前面的分析中也介紹過MethodReplace的內容格式,可參考如下:

而在進行Replace Method是,是在Native層做:

在JNI的程式碼中,支援Dalvik與ART,這時它的程式碼結構:

其修復原理就是從記憶體中找出原來函式指令指標,讓它指向新的函式地址:


上面的meth變數便是我們bug.apk中的函式的控制代碼,target便是.aptach檔案中函式的控制代碼。

而insns是函式指令地址的指標,解釋如下:

到此函式替換的原理就水落石出了,就是函式Hook。

很犀利的做法。

【總結】

所以總結一下補丁執行的原理就是:

在執行時,讀取patch檔案中的函式,將它的函式指令地址賦給APK中的函式。

這樣不就等於替換了原來的函式麼?那麼bug也就可以被消除了。。。

當然這一切都是在記憶體中進行的,不會對本地的APK有任何影響。

相關推薦

關於Android APP線上修復bug方案調研()(AndFix)

調研背景:      App釋出出去後,如果發現有緊急或重要bug如何進行修復呢?      重新發布一版APK?但這樣代價太大....       那麼有沒有一種方案能夠不用更新整個APK,而只把伺服器上的很小的補丁檔案下載下來進行修復bug呢?       本文的調研也

Unity Android APP il2cpp更完美解決方案

1. 簡介 這是Unity Android APP il2cpp熱更完美解決方案的Demo(Git地址)的說明。 和現有的熱更解決方案不同的是,他不會引入多餘的語言(只是UnityScript,c#…),對Unity程式設計和編碼沒有任何限制。你可以在預置和場景裡的GameObjec

Android客戶端外掛化修復各種方案對比和最全總結

2016年不能扯幾句熱修復和外掛化都不好意思說自己是做 Android 的,雖然我對這個技術不怎麼感興趣,奈何業務需要也得深入的研究一下,本文記錄我對熱修復的外掛化的學習和研究。 技術背景 外掛化解決的問題 減小主包大小 不發版上新功能 獨立開發載入

Android Dex 分包+修復(QQ空間技術方案

import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException;

線上修復技術

images sse idt classes lib 反射 png 兩個 logs 沒學會、沒接觸的時候感覺很難,學會了也就沒那麽難 1.前言 2.相關技術 阿裏巴巴 AndFix、Dexposed QQ空間 超級補丁 微信 Tinker (一)

Android之移動修復

com don load query 監聽 基線 mis tps 事件 阿裏雲最近推出了移動熱修復服務,聽說這個服務傻瓜式接入,性能相對較好,對新技術比較好奇的我決定嘗試一下。 移動熱修復.png 首先,需要開通這個服務,創建應用 創建應用.png 然後,在

介紹自己的一個Android插樁修復框架項目QuickPatch

pid android版本 通過 fly 特性 put javassist 執行 自動生成 QuickPatch項目地址:https://gitee.com/egg90/QuickPatch 和 https://github.com/eggfly/QuickPatch 同步

Android 代碼修復詳解

value file final ext.get vat 根據 tde arch x文件 java:類加載原理:當類加載器收到加載類或資源的請求時,通常都是先委托給父類加載器加載,也就是說只有當父類加載器找不到指定類或資源時,自身才會執行實際的類加載過程,具體的加載過程如下

Android app 線上更新那點事兒(適配Android6.0、7.0、8.0)

一、前言 app線上更新是一個比較常見需求,新版本釋出時,使用者進入我們的app,就會彈出更新提示框,第一時間更新新版本app。線上更新分為以下幾個步驟: 1, 通過介面獲取線上版本號,versionCode 2, 比較線上的versionCode 和本地的versi

android修復與外掛化()

簡介 目前android技術最前沿莫屬熱修復與外掛化的技術點,當下用得最多的就是阿里的Andfix,和微信的Tinker框架,針對原始碼的實現,再次做個記錄。 熱修復給我們解決的問題 剛上線的APP應用,由於測試的疏忽,發現了一個嚴重的bug

Android Studio與Android SDK 線上更新的解決方案(1.3.2)

1、Android Studio更新 問題:在Android Studio中,點選help-Check for Update,會出現如下錯誤: 解決方案:開啟Android Studio的安裝目錄,

Android 修復與外掛化 】帶你入門Android外掛化(附demo)

本文為博主Colin原創文章,歡迎轉載。 https://blog.csdn.net/colinandroid/article/details/79431502   一. 背景 Android外掛化作為每個合格的Android程式設計師都必須會的技術,被各大廠廣泛使用。隨著各大廠對

Android APP效能優化十大方案

Android系統的手機市場佔有率目前來說還是最大的,因此基於Android開發的App數量也是很龐大的。那麼,如何能開發出更高效能的Android App?相信是軟體開發公司以及廣大程式設計師們頭疼的一大難題。今天,就給大家提供幾個提高Android App效能的技巧。

Android 修復與外掛化

熱修復 : 支付寶、優酷、微信 剛釋出的應用就發現了比較嚴重的bug 有一些小的功能想即時推送給使用者去使用 外掛化 : 美團、淘寶、酷狗 解決應用越來越大所帶來的各種技術限制,方法數超過65

Android打補丁 修復(HotFix)小結

需求場景:    當我們的app釋出以後,發現有bug,比如維護資料錯誤,應用邏輯錯誤,嚴重的可能引發應用崩潰。這時修改應用可能只需要修改幾行程式碼,或者某個方法就可以搞定。以前為了解決這樣的

修復現有方案的比較】

2015年以來,Android開發領域裡對熱修復技術的討論和分享越來越多,同時也出現了一些不同的解決方案,如QQ空間補丁方案、阿里AndFix以 及微信Tinker,它們在原理各有不同,適用場景各異,到底採用哪種方案,是開發者比較頭疼的問題。本文希望通過介紹QQ空間補丁、

淺談修復QZone 、 阿里的AndFix 、 騰訊的Tinker

目前熱修復的技術基本上有  QZone  、  阿里的AndFix   、 騰訊的Tinker  等。 下面我們簡單介紹下這幾種熱修復方案: QZone    採用的是dex分包方案,多dex載入原

android查詢幾十萬條資料的調研()

此次調研分兩步走吧, 先從測試的角度看(一), 再從原始碼的角度看(二)(待續). 下面的是測試程式碼: SQLiteUtils.java package com.johnsoft.app.temp; import android.content.Context; import

Android線上bug修復分析

針對app線上修復技術,目前有好幾種解決方案,開源界往往一個方案會有好幾種實現。重複的實現會有造輪子之嫌,但分析解決方案在技術上的探索和衍變,這輪子還是值得去推動的 關於Hot Fix技術 Hot Fix技術,簡單來說就是針對線上已釋出app出現

Android修復 Dex注入實現靜默消滅bug

      當app上線後發現緊急bug,如果重新發布版本週期比較長,並且對使用者體驗不好,此時熱修復就派上用場了。熱修復就是為緊急bug而生,能夠快速修復bug,並且使用者無感知。針對熱修復,阿里系先後推出AndFix、HotFix、SophFix,騰訊系也推出QQ空間超級補丁