縮減 OTA 大小

本頁面說明新增至 AOSP 的變更,可減少建構版本之間不必要的檔案變更。 如果裝置實作者維護自己的建構系統,可以參考這項資訊,縮減無線 (OTA) 更新的大小。

Android OTA 更新有時會包含與程式碼變更不符的變更檔案。 這些其實是建構系統構件。如果從不同目錄或機器,在不同時間建構相同程式碼,產生大量變更的檔案,就可能發生這種情況。這類多餘檔案會增加 OTA 修補程式的大小,且難以判斷哪些程式碼已變更。

為提高 OTA 內容的透明度,AOSP 納入的建構系統變更旨在縮減 OTA 修補程式的大小。已消除建構作業之間不必要的檔案變更,OTA 更新只包含修補程式相關檔案。AOSP 也包含建構差異工具,可篩除常見的建構相關檔案變更,提供更乾淨的建構檔案差異,以及區塊對應工具,可協助您保持區塊分配一致性。

建構系統可能會以幾種方式建立過大的修補程式。為解決這個問題,Android 8.0 以上版本導入了新功能,可減少每個檔案差異的修補程式大小。減少 OTA 更新套件大小的改善項目包括:

  • 在非 A/B 裝置更新中,使用 ZSTD (適用於完整圖片的通用無損壓縮演算法)。ZSTD 可透過提高壓縮層級,自訂更高的壓縮率。壓縮層級是在 OTA 生成時間設定,可以傳遞 --vabc_compression_param=zstd,$COMPRESSION_LEVEL 旗標來設定。
  • 增加 OTA 期間使用的壓縮視窗大小。如要設定壓縮視窗大小上限,請在裝置的 .mk 檔案中自訂建構參數。這個變數會設為 PRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR := 262144
  • 使用 Puffin 重新壓縮,這項工具可針對 deflate 串流執行確定性修補,並處理 A/B OTA 更新產生作業的壓縮和差異函式。
  • 變更差異產生工具的使用方式,例如如何使用 bsdiff 程式庫壓縮修補程式。在 Android 9 以上版本中,bsdiff 工具會選取可為修補程式提供最佳壓縮結果的壓縮演算法。
  • update_engine的改善措施可減少記憶體用量,適用於 A/B 裝置更新的修補程式。

以下各節將討論影響 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 是透過雜湊處理預先剝除的二進位檔所產生,因此如果偵錯符號有所變更,.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 時間戳記。

這項新工具 (位於 /platform/build/+/android16-release/tools/ziptime/) 會重設 ZIP 標頭中的正常時間戳記。ziptime詳情請參閱 README 檔案

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

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

版本字串

問題:APK 版本字串通常會附加 BUILD_NUMBER 至硬式編碼版本。即使 APK 中沒有其他變更,APK 仍會因此不同。

解決方法:從 APK 版本字串中移除建構編號。

這些檢查包括:

啟用裝置端驗證計算

如果裝置已啟用 dm-verity,OTA 工具會自動擷取驗證設定,並啟用裝置端驗證運算。這樣一來,系統就能在 Android 裝置上計算驗證區塊,而不是將驗證區塊以原始位元組的形式儲存在 OTA 封裝中。2 GB 分割區的驗證區塊約可使用 16 MB。

不過,在裝置上計算驗證資訊可能需要很長時間。具體來說,前向錯誤更正碼可能需要很長時間。在 Pixel 裝置上,這項程序通常最多需要 10 分鐘。在低階裝置上,可能需要較長的時間。如要停用裝置端完整性計算,但仍啟用 dm-verity,可以在產生 OTA 更新時,將 --disable_fec_computation 傳遞至 ota_from_target_files 工具。這項標記會在 OTA 更新期間停用裝置上的完整性計算。 這會縮短 OTA 安裝時間,但會增加 OTA 套件大小。如果裝置未啟用 dm-verity,傳遞這個標記不會有任何作用。

一致的建構工具

問題:產生已安裝檔案的工具必須保持一致 (特定輸入內容應一律產生相同輸出內容)。

解決方案/範例:您必須在下列建構工具中進行變更:

使用建構差異工具

如果無法避免建構相關檔案變更,AOSP 包含建構差異工具 target_files_diff.py,可用於比較兩個檔案套件。這項工具會對兩個建構作業執行遞迴差異,並排除常見的建構相關檔案變更,例如

  • 建構輸出內容的預期變更 (例如因建構編號變更而異)。
  • 這是因為目前建構系統的已知問題所致。

如要使用建構差異工具,請執行下列指令:

target_files_diff.py dir1 dir2

dir1dir2 是基本目錄,包含每個建構作業的已解壓縮目標檔案。

保持區塊分配一致

以特定檔案來說,雖然兩個建構版本之間的內容相同,但實際保存資料的區塊可能已變更。因此,更新程式必須執行不必要的 I/O,才能移動區塊以進行 OTA 更新。

在虛擬 A/B OTA 更新中,不必要的 I/O 會大幅增加儲存空間需求,以儲存寫入時複製的快照。在非 A/B OTA 更新中,為 OTA 更新移動區塊會增加更新時間,因為區塊移動會導致更多 I/O。

為解決這個問題,Google 在 Android 7.0 中擴充了 make_ext4fs 工具,確保各個建構版本之間的區塊分配一致。make_ext4fs 工具接受選用的 -d base_fs 旗標,在產生 ext4 映像檔時,嘗試將檔案分配到相同區塊。您可以從先前建構作業的目標檔案 ZIP 檔案中,擷取區塊對應檔案 (例如 base_fs 對應檔案)。每個 ext4 分區在 IMAGES 目錄中都有一個 .map 檔案 (例如,IMAGES/system.map 對應於 system 分區)。接著,您可以簽入這些 base_fs 檔案,並透過 PRODUCT_<partition>_BASE_FS_PATH 指定,如以下範例所示:

  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 套件時,可能已從應用程式商店直接取得更新版應用程式,甚至是更新版本。