減少 OTA 大小

本頁描述了添加到 AOSP 中的更改,以減少建置之間不必要的文件更改。維護自己的建置系統的設備實施者可以使用此資訊作為減少無線 (OTA) 更新大小的指南。

Android OTA 更新有時會包含與程式碼變更不對應的變更檔。它們實際上是建構系統工件。當在不同時間、不同目錄或不同機器上建置的相同程式碼產生大量變更的檔案時,可能會發生這種情況。此類多餘的檔案會增加 OTA 補丁的大小,並導致難以確定哪些程式碼發生了變更。

為了使 OTA 的內容更加透明,AOSP 包括旨在減少 OTA 補丁大小的建造系統變更。版本之間不必要的檔案變更已被消除,OTA 更新中僅包含與修補程式相關的檔案。 AOSP 還包括一個構建差異工具(可過濾掉常見的構建相關文件更改,以提供更清晰的構建文件差異)和一個塊映射工具(可幫助您保持塊分配一致)。

建置系統可以透過多種方式創建不必要的大補丁。為了緩解這個問題,在 Android 8.0 及更高版本中,實作了新功能來減少每個檔案差異的修補程式大小。減少 OTA 更新包大小的改進包括:

  • 使用Brotli ,這是一種通用的無損壓縮演算法,用於非 A/B 裝置更新上的完整影像。 Brotli可以客製化以優化壓縮。在檔案系統中由兩個或多個區塊組成的較大更新(例如, system.img )中,設備製造商或合作夥伴可以添加自己的壓縮演算法,並且可以對相同更新的不同區塊使用不同的壓縮演算法.
  • 使用Puffin重新壓縮,這是用於 deflate 流的確定性修補工具,可處理 A/B OTA 更新產生的壓縮和 diff 函數。
  • 更改了增量生成工具的使用方式,例如如何使用bsdiff庫來壓縮補丁。在 Android 9 及更高版本中, bsdiff工具會選擇可為補丁提供最佳壓縮結果的壓縮演算法。
  • update_engine的改進導致應用程式補丁進行 A/B 裝置更新時消耗的記憶體更少。
  • 改進了分割大型 zip 檔案以進行基於區塊的 OTA 更新。 imgdiff中的模式根據條目名稱分割超大 APK 檔案。與線性分割檔案並使用bsdiff工具壓縮檔案相比,這會產生更小的補丁。

以下部分討論影響 OTA 更新大小的各種問題、其解決方案以及 AOSP 中的實作範例。

文件順序

問題:當要求提供目錄中的文件清單時,檔案系統不保證文件順序,儘管對於相同的簽出通常是相同的。 ls等工具預設會對結果進行排序,但findmake等指令使用的通配符函數不會排序。在使用這些工具之前,您必須對輸出進行排序。

解決方案:當您使用帶有通配符功能的findmake工具時,請在使用這些命令之前對它們的輸出進行排序。在Android.mk檔案中使用$(wildcard)$(shell find)時,也要對它們進行排序。有些工具(例如 Java)會對輸入進行排序,因此在對檔案進行排序之前,請先驗證您使用的工具是否尚未執行此操作。

範例:使用內建的all-*-files-under宏在核心建置系統中修復了許多實例,其中包括all-cpp-files-under (因為多個定義分散在其他 makefile 中)。詳細資訊請參考以下內容:

建置目錄

問題:更改建置內容的目錄可能會導致二進位檔案不同。 Android 建置中的大多數路徑都是相對路徑,因此 C/C++ 中的__FILE__不是問題。但是,偵錯符號預設對完整路徑名進行編碼,並且.note.gnu.build-id是透過對預先剝離的二進位檔案進行哈希處理生成的,因此如果偵錯符號發生變化,它也會發生變化。

解決方案: AOSP 現在使調試路徑相對。有關詳細信息,請參閱 CL: https ://android.googlesource.com/platform/build/+/6a66a887baadc9eb3d0d60e26f748b8453e27a02 。

時間戳

問題:建置輸出中的時間戳記會導致不必要的檔案變更。這種情況很可能發生在以下位置:

  • C 或 C++ 程式碼中的__DATE__/__TIME__/__TIMESTAMP__巨集。
  • 時間戳嵌入基於 zip 的檔案中。

解決方案/範例:若要從建置輸出中刪除時間戳,請使用下面C/C++ 中的 __DATE__/__TIME__/__TIMESTAMP__ 中給出的說明。以及檔案中嵌入的時間戳記

C/C++ 中的 __DATE__/__TIME__/__TIMESTAMP__

這些巨集總是為不同的構建產生不同的輸出,所以不要使用它們。以下是消除這些巨集的一些選項:

檔案中嵌入時間戳記(zip、jar)

Android 7.0 透過在zip指令的所有使用中新增-X解決了 zip 檔案中嵌入時間戳記的問題。這從 zip 檔案中刪除了建構器的 UID/GID 和擴充 Unix 時間戳記。

新工具ziptime (位於/platform/build/+/main/tools/ziptime/ )會重設 zip 標頭中的正常時間戳記。有關詳細信息,請參閱README 文件

signapk工具為 APK 檔案設定時間戳,該時間戳可能因伺服器時區而異。有關詳細信息,請參閱 CL https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028

版本字串

問題: APK 版本字串通常會在其硬編碼版本後附加BUILD_NUMBER 。即使 APK 中沒有其他任何變化,APK 仍然會有所不同。

解決方案:從 APK 版本字串中刪除內部版本號。

例子:

啟用裝置上的驗證計算

如果您的裝置上啟用了dm-verity ,則 OTA 工具會自動取得您的驗證配置,並啟用裝置上的驗證計算。這允許在 Android 裝置上計算 verity 區塊,而不是作為原始位元組儲存在 OTA 套件中。對於 2GB 分割區,Verity 區塊可以使用大約 16MB。

然而,在設備上計算驗證可能需要很長時間。具體來說,前向糾錯碼可能需要很長時間。在 Pixel 設備上,通常需要長達 10 分鐘的時間。在低端設備上可能需要更長的時間。如果您想要停用裝置上的 verity 運算,但仍啟用 dm-verity,則可以透過在產生 OTA 更新時將--disable_fec_computation傳遞給ota_from_target_files工具來實現。該標誌會在 OTA 更新期間停用裝置上的驗證計算。它減少了 OTA 安裝時間,但增加了 OTA 套件大小。如果您的裝置未啟用 dm-verity,則傳遞此標誌無效。

一致的建構工具

問題:產生已安裝檔案的工具必須一致(給定的輸入應始終產生相同的輸出)。

解決方案/範例:以下建置工具需要更改:

使用建構差異工具

對於無法消除與建置相關的檔案變更的情況,AOSP 包含一個建置差異工具target_files_diff.py ,用於比較兩個檔案包。該工具在兩個建置之間執行遞歸差異,排除常見的與建置相關的檔案更改,例如

  • 建置輸出的預期變化(例如,由於建構號更改)。
  • 由於目前建置系統中的已知問題而發生的變更。

若要使用建置 diff 工具,請執行以下命令:

target_files_diff.py dir1 dir2

dir1dir2是包含每個建置提取的目標檔案的基底目錄。

保持區塊分配一致

對於給定文件,儘管其內容在兩次建置之間保持相同,但保存資料的實際區塊可能已更改。因此,更新程式必須執行不必要的 I/O 來移動區塊以進行 OTA 更新。

在虛擬 A/B OTA 更新中,不必要的 I/O 會大幅增加儲存寫入時複製快照所需的儲存空間。在非 A/B OTA 更新中,移動區塊進行 OTA 更新會延長更新時間,因為區塊移動會產生更多 I/O。

為了解決這個問題,在 Android 7.0 中,Google 擴充了make_ext4fs工具,以保持跨建置的區塊分配一致。 make_ext4fs工具接受可選的-d base_fs標誌,該標誌在產生ext4映像時嘗試將檔案指派到相同的區塊。您可以從先前建置的目標檔案的 zip 檔案中提取區塊映射檔案(例如base_fs映射檔案)。對於每個ext4分區, IMAGES目錄下都有.map檔(例如, IMAGES/system.map對應system分區)。然後可以透過PRODUCT_<partition>_BASE_FS_PATH簽入並指定這些base_fs文件,如本範例所示:

  PRODUCT_SYSTEM_BASE_FS_PATH := path/to/base_fs_files/base_system.map
  PRODUCT_SYSTEM_EXT_BASE_FS_PATH := path/to/base_fs_files/base_system_ext.map
  PRODUCT_VENDOR_BASE_FS_PATH := path/to/base_fs_files/base_vendor.map
  PRODUCT_PRODUCT_BASE_FS_PATH := path/to/base_fs_files/base_product.map
  PRODUCT_ODM_BASE_FS_PATH := path/to/base_fs_files/base_odm.map

雖然這無助於減小整體 OTA 套件大小,但它確實透過減少 I/O 量來提高 OTA 更新效能。對於虛擬 A/B 更新,它大大減少了應用 OTA 所需的儲存空間量。

避免更新應用程式

除了最大限度地減少建置差異之外,您還可以透過排除透過應用程式商店取得更新的應用程式的更新來減少 OTA 更新大小。 APK 通常包含裝置上各個分區的重要部分。在 OTA 更新中包含應用程式商店更新的應用程式的最新版本可能會對 OTA 套件產生很大的影響,並且為用戶帶來的好處很少。當用戶收到 OTA 包時,他們可能已經擁有直接從應用程式商店收到的更新應用程式或更新版本。