技術分享PPT: 高性能diff&patch算法
-- 如何將微信Apk的官方增量包20.4M縮小到7.0M
作者: [email protected] 2018.03.16
什麼是diff&patch算法
- 原理抽象概述: … …
3種有效的diff算法
- 增量壓縮流
- 同步流
- 覆蓋線流
其他:按行、按文件等…
增量壓縮diff算法
- 最容易實現的可以自己diy出來的一種有效算法
- 尋找一種高效的基礎壓縮算法
- 實現技巧:
- 拼接old+new一起壓縮,輸出new部分壓縮得到的編碼爲補丁;patch時先壓縮old並和補丁拼一起解壓縮,丟棄前面old大小的數據,後面的就是新生成的new
- 優缺點:
- 容易實現,算法選擇的好時效果很贊;適應範圍較窄(數據較大時補丁可能突然異常變大),因爲要壓縮速度可能慢等
覆蓋線diff算法
- BsDiff
- HDiffPatch
- 實現原理:
- 二維矩陣概念
- 覆蓋線概念
- 後綴數組(QuickSort\libdivsufsort)
- 優缺點:
- 補丁小、diff內存佔用大、運行慢、patch快
- patch內存佔用O(m+n)複雜度的誤解: 這只是BsDiff的具體實現問題;HDiffPatch就可以做到實際內存佔用O(1)的patch過程;(HDiffPatch也提供了降低diff時間和空間複雜度的實現版本:同步diff算法的實現)
- 小胡瓜Courgette:
- 原理:針對程序,反編譯old和new、diff源代碼、反編譯old並patch源代碼、編譯成new
同步diff算法
- 原理:分塊hash和roll hash的對比
- 一些實現:同步工具、xdelta?、HDiffPatch
- 優缺點:
- 可以支持動態CS模式(甚至允許C損壞)、速度快、可以支持超大文件;(xdelta對超大文件支持不好)
Apk的diff算法選擇
- zip、jar、apk的關係 (另外: ipa)
- Jar包簽名(Apk v1 Sign)
- BsDiff 、HDiffPatch
- 爲什麼微信Apk663版到665版的升級包是20.4M
- 遇到的適應問題:壓縮算法破壞了“現場”
- 直觀的解決思路:zip包的針對性優化
- 將zip抽象成未壓縮狀態的數據交給diff算法,patch時輸出標準zip包
如何支持嚴苛的Apk V2版簽名
- Apk v2 Sign介紹
- 額外:渠道包失效? 現在該如何在包中“夾帶私貨”
- 增量更新解決思路:
- newZip=AndroidSDK#apksigner(ApkNormalized(newZip)) before ZipDiff
- patch重建newZip時byte by byte的相等保證;
- 風險提示、安全保證手段
- ApkDiffPatch方案:
- Zip(Jar,Apk) file by file Diff & Patch, create minimal differential, support apk v2 sign & Jar sign(apk v1).
有了BsDiff或HDiffPatch爲什麼還需要ApkDiffPatch?
ApkDiffPatch: v1.0
BsDiff: v4.3
HDiffPatch: v2.2.6
Google Play patches: https://github.com/andrewhayden/archive-patcher v1.0
(test by https://github.com/googlesamples/apk-patch-size-estimator )
======================================================================================
BsDiff HDiffPatch archive-patcher ApkDiffPatch
oldVersion -> newVersion newSize (bzip2) (zlib) (gzip) (zlib) (lzma)
--------------------------------------------------------------------------------------
v63->chrome-64-0-3282-123.apk 43879588 32916357 32621974 18776996 15995242 13896562
chrome-64-0-3282-137.apk 43879588 28895294 28538751 1357320 1341073 1149331
chrome-65-0-3325-109.apk 43592997 31771385 31540550 16427116 14415021 12356765
v70->google-maps-9-71-0.apk 50568872 37992141 37531799 17293163 14562607 11430622
google-maps-9-72-0.apk 54342938 41897706 41475595 21301751 18752320 14066134
v660->weixin661android1220.apk 61301316 17565557 17372003 1927833 1794219 1659286
weixin662android1240.apk 63595334 38349926 38025483 22100454 18392769 15556315
weixin663android1260.apk 63595326 11614415 11531258 1044656 937920 940060
weixin665android1280.apk 63669882 21423459 21176790 9621032 9003472 7392063
--------------------------------------------------------------------------------------
Average Compression 100.0% 56.3% 55.8% 23.5% 20.4% 16.8%
======================================================================================
額外:下載服務商的可能優化策略討論
無法重新打包和簽名的情況下如何支持v2簽名Apk包的類似優化增量包?
- 收集常見的兼容壓縮算法庫;
- 動態計算出apk使用的可能壓縮庫和其壓縮參數,以保證patch時byteByByte還原; 這樣能解決絕大部分Apk的升級;否則剩下的Apk就退回類似直接diff的方案;
Google Play patches : archive-patcher方案:
- file by file Diff & Patch; is an open-source project that allows space-efficient patching of zip archives. Many common distribution formats (such as jar and apk) are valid zip archives; archive-patcher works with all of them.