本頁說明 Android 開放原始碼計畫新增的變更,減少版本之間不必要的檔案變更。 維護自有建構系統的裝置實作人員可將這項資訊做為指引 ,藉此減少無線更新 (OTA) 的大小。
Android OTA 更新偶爾會包含不會對應至程式碼變更的已變更檔案。 實際上就是建構系統構件當同一個程式碼以不同的建構方式建構時,就可能發生這種情況 在不同目錄或不同機器上 都會產生大量變更 檔案。這類超額檔案會增加 OTA 修補程式的大小,且會難以判斷 有哪些變更的程式碼
為了讓 OTA 內容更加透明,Android 開放原始碼計畫納入了 以縮減 OTA 修補程式的大小。版本之間出現不必要的檔案變更 且只有修補程式相關檔案會納入 OTA 更新中。Android 開放原始碼計畫也提供 建構差異比較工具:篩除常見的建構相關 提供更簡潔的建構檔案差異 封鎖對應工具,協助維持封鎖分配 保持一致
建構系統可透過多種方式建立不必要的大型修補程式。為減輕影響, Android 8.0 以上版本導入了新功能,以縮減每個修補程式的大小 檔案差異減少 OTA 更新套件大小的改善項目包括:
-
使用 ZSTD 這套通用用途、無損壓縮演算法完整處理
A/B 以外裝置更新的映像檔。可自訂 ZSTD,適用於更高層級
藉此增加壓縮率已透過 OTA 設定壓縮等級
並且可以在
--vabc_compression_param=zstd,$COMPRESSION_LEVEL
-
增加 OTA 中使用的壓縮視窗大小。壓縮時長上限
您可以在裝置
.mk
檔案中自訂建構參數來設定。這個 變數設為PRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR := 262144
- 使用 Puffin 重新壓縮這項確定性修補工具 串流,可處理 A/B OTA 更新產生作業的壓縮和差異函式。
-
差異產生工具使用方式的變更,例如
bsdiff
敬上 程式庫用於壓縮修補程式在 Android 9 以上版本中,bsdiff
工具會選擇壓縮演算法 最佳壓縮結果。 -
改善
update_engine
能減少執行 A/B 裝置更新修補程式時消耗的記憶體。
以下各節討論各種會影響 OTA 更新大小的問題及其解決方案 以及 Android 開放原始碼計畫的實作範例
檔案順序
問題:檔案系統在要求列出清單時,不保證檔案的順序
多個目錄檔案,而同一個結帳頁面通常會是相同的。例如
ls
預設會排序結果,但這類指令使用的萬用字元函式,
因為 find
和 make
都不會排序。使用這些工具前,您必須先將
這些輸出內容
解決方案:當您使用 find
和
make
搭配萬用字元函式,請先排序這些指令的輸出內容,再使用
具體做法是指示 Kubernetes 建立並維護
一或多個代表這些 Pod 的物件在以下位置使用 $(wildcard)
或 $(shell find)
時:
Android.mk
個檔案,請一併加以排序。有些工具 (例如 Java) 會排序輸入
排序檔案前,請確認目前使用的工具尚未執行。
範例:在核心建構系統中,許多執行個體是使用
內建的 all-*-files-under
巨集,其中包含
all-cpp-files-under
(因為數個定義已分散在其他 makefile)。
詳情請參閱下列資源:
- https://android.googlesource.com/platform/build/+/4d66adfd0e6d599d8502007e4ea9aaf82e95569f
- https://android.googlesource.com/platform/build/+/379f9f9cec4fe1c66b6d60a6c19fecb81b9eb410
- https://android.googlesource.com/platform/build/+/7c3e3f8314eec2c053012dd97d2ae649ebeb5653
- https://android.googlesource.com/platform/build/+/5c64b4e81c1331cab56d8a8c201f26bb263b630c
建構目錄
問題:變更建構內容的目錄可能會導致
兩者的二進位檔不同Android 建構作業中的大多數路徑都是相對路徑,因此
C/C++ 中的 __FILE__
不會發生問題。不過,偵錯符號會將
預設路徑名稱,且 .note.gnu.build-id
是從
因此,如果偵錯符號有變動,就會發生變化。
解決方案:Android 開放原始碼計畫現在會建立相對的偵錯路徑。詳情請參閱 CL: https://android.googlesource.com/platform/build/+/6a66a887baadc9eb3d0d60e26f748b8453e27a02。
時間戳記
問題:建構輸出內容中的時間戳記會導致不必要的檔案變更。 這很可能會在下列位置發生:
- C 或 C++ 程式碼中的
__DATE__/__TIME__/__TIMESTAMP__
巨集。 - 內嵌於 ZIP 封存檔中的時間戳記。
解決方案/範例:如要從建構輸出內容中移除時間戳記,請使用 操作說明請見 C/C++ 中的__DATE__/__TIME__/__TIMESTAMP__。和 封存檔中的嵌入時間戳記。
C/C++ 中的 __DATE__/__TIME__/__TIMESTAMP__
這些巨集一律會為不同的版本產生不同的輸出內容,因此請勿使用。這裡 下列是幾個不需要這些巨集的選項:
- 請移除。範例請參照 https://android.googlesource.com/platform/system/core/+/30622bbb209db187f6851e4cf0cdaa147c2fca9f。
- 如要唯一識別執行中的二進位檔,請參閱 ELF 標頭中的版本 ID。
-
如要確認 OS 的建構時間,請參閱
ro.build.date
(適用於 除了漸進式版本之外,其他全貌,因此可能不會更新這個日期)。如需範例,請參閱 到 https://android.googlesource.com/platform/external/libchrome/+/8b7977eccc94f6b3a3896cd13b4aeacbfa1e0f84。
封存檔案中的嵌入時間戳記 (zip、jar)
Android 7.0 修正了 ZIP 封存檔中嵌入時間戳記的問題,
-X
可以全面使用 zip
指令。這移除了
和 ZIP 檔案中的擴充 Unix 時間戳記。
新工具 ziptime
(位於
/platform/build/+/main/tools/ziptime/
) 會重設 ZIP 標頭中的一般時間戳記。詳情請參閱
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 版本字串中移除版本號碼。
這些檢查包括:
- https://android.googlesource.com/platform/packages/apps/Camera2/+/5e0f4cf699a4c7c95e2c38ae3babe6f20c258d27
- https://android.googlesource.com/platform/build/+/d75d893da8f97a5c7781142aaa7a16cf1dbb669c
啟用裝置端驗證功能
如果為 dm-verity ,接著 OTA 工具會自動選擇您的驗證設定, 啟用裝置端驗證功能這可讓 Android 計算驗證區塊 裝置,而不是在 OTA 套件中儲存為原始位元組。雜訊方塊可以使用 2 GB 分區約為 16 MB
不過,在裝置上運算結果可能需要相當長的時間。具體來說
錯誤修正程式碼可能需要較長的時間才能完成。以 Pixel 裝置來說,大小上限為 10
分鐘。如果是低階裝置,所需時間可能會更長。如果想要停用裝置端驗證
但仍然啟用 dm-verity 的功能
對 ota_from_target_files
工具執行 --disable_fec_computation
權限
再產生 OTA 更新。這個標記會在 OTA 更新期間停用裝置端驗證運算功能。
可縮短 OTA 安裝時間,但增加 OTA 套件大小。如果您的裝置不支援
已啟用 dm-verity,傳送這個標記不會有任何效果。
一致的建構工具
問題:產生已安裝檔案的工具必須一致 (在指定 輸入內容應一律產生相同的輸出內容)。
解決方案/範例:下列建構工具需要進行變更:
- NOTICE 檔案建立者「通知」檔案建立者已變更為建立 可重現的「通知」集合。請參閱 CL: https://android.googlesource.com/platform/build/+/8ae4984c2c8009e7a08e2a76b1762c2837ad4f64。
- Java Android 編譯器套件 (Jack)。Jack 工具鍊需要更新 可處理偶爾產生的建構函式排序變更。確定性存取子的 建構函式已新增至工具鍊: https://android.googlesource.com/toolchain/jack/+/056a5425b3ef57935206c19ecb198a89221ca64b。
- ART AOT 編譯器 (dex2oat)。ART 編譯器二進位檔收到更新, 新增了建立確定性圖片的選項: https://android.googlesource.com/platform/art/+/ace0dc1dd5480ad458e622085e51583653853fb9。
-
libpac.so 檔案 (V8)。每個版本
/system/lib/libpac.so
檔案,因為每個版本的 V8 快照有所變更。 移除快照: https://android.googlesource.com/platform/external/v8/+/e537f38c36600fd0f3026adba6b3f4cbcee1fb29。 - 應用程式 dexopt (.odex) 檔案。DEX 前置處理 (.odex) 檔案 包含在 64 位元系統上未初始化的邊框間距。以下為修正後的結果: https://android.googlesource.com/platform/art/+/34ed3afc41820c72a3c0ab9770be66b6668aa029。
使用建構差異比較工具
如果無法消除建構相關檔案變更,Android 開放原始碼計畫會納入
建構差異比較工具
target_files_diff.py
以便用於比較兩個檔案套件這個工具會對兩個指標執行遞迴差異
建構作業,但不包括常見的建構相關檔案變更
- 預期的建構輸出內容變更 (例如因版本編號變更)。
- 因目前建構系統的已知問題而所做的變更。
如要使用建構差異比較工具,請執行下列指令:
target_files_diff.py dir1 dir2
dir1
和 dir2
是包含所擷取目標的基本目錄
適用於個別版本的檔案
保持區塊分配一致
對特定檔案而言,雖然其內容在兩個版本之間保持不變,但實際區塊 暫存資料可能有所變更因此,更新程式必須執行不必要的 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
圖片您可以將區塊對應檔 (例如
base_fs
對應檔案)ZIP 檔案,對於每項
ext4
分區,有 .map
檔案位於
IMAGES
目錄 (例如 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 套件大小,但確實能改善 OTA 更新 藉此降低 I/O 效能虛擬 A/B 更新大幅降低 套用 OTA 所需的儲存空間容量
避免更新應用程式
除了盡量減少建構差異外,您還可以排除更新,藉此縮減 OTA 更新大小 可讓你透過應用程式商店更新應用程式APK 通常屬於 裝置上有多個分區包含可透過應用程式更新的最新版應用程式 可能會大幅影響 OTA 套件的規格,而且只會對少量使用者造成太大影響 好處。當使用者收到 OTA 套件時,他們可能已經已安裝新版應用程式,或 也就是直接從應用程式商店取得