動態系統更新 (DSU) 可讓您建立具有 ,即可從網際網路下載並嘗試執行,而不會有損毀的風險 目前的系統映像檔本文說明如何支援 DSU。
核心需求
詳情請見 實作動態分區 滿足核心需求
此外,DSU 採用 device-mapper-verity (dm-verity) 核心功能 來驗證 Android 系統映像檔因此,您必須啟用下列核心 設定:
CONFIG_DM_VERITY=y
CONFIG_DM_VERITY_FEC=y
分區要求
自 Android 11 起,DSU 要求使用 /data
分區,藉此使用 F2FS 或 ext4 檔案系統。F2FS 的表現更佳,
但這兩者的差異不大。
以下舉例說明更新 Pixel 需要多久時間 裝置:
- 使用 F2FS:
- 109 秒,8G 使用者,867M,檔案系統類型:F2FS: encryption=aes-256-xts:aes-256-cts
- 104 秒,8G 使用者,867M,檔案系統類型:F2FS: encryption=ice
- 使用 ext4:
- 135 秒,8G 使用者,867M,檔案系統類型:ext4: encryption=aes-256-xts:aes-256-cts
如果平台花費的時間比平常久,請檢查掛接程序 標記內含任何會進行「同步」寫入的旗標,您也可以指定「非同步」 以便提高成效
必須使用 metadata
分區 (16 MB 以上),才能儲存相關資料
安裝在已安裝的映像檔上必須在第一個階段掛接時進行掛接。
userdata
分區必須使用 F2FS 或 ext4 檔案系統。使用 F2FS 時
包含所有 F2FS 相關修補程式
Android 通用核心。
DSU 是以核心/常見 4.9 進行開發與測試。建議使用 核心 4.9 以上版本。
供應商 HAL 行為
Weaver HAL
武器 HAL 提供固定數量的運算單元,用於儲存使用者金鑰。DSU 會耗用兩個額外的主要運算單元如果 OEM 有武器 HAL 足以容納一般系統映像檔 (GSI) 和主機映像檔。
總機 HAL
總機人員 HAL 必須
支援大型 USER_ID
值,因為 GSI 會將 UID 偏移至 HAL
+1000000。
驗證啟動程序
如要支援啟動開發人員 GSI 映像檔
處於鎖定狀態,而未停用
驗證開機程序,並加入開發人員 GSI 金鑰。
新增至 device/<device_name>/device.mk
檔案:
$(call inherit-product, $(SRC_TARGET_DIR)/product/developer_gsi_keys.mk)
復原保護機制
使用 DSU 時,下載的 Android 系統映像檔必須比
目前的系統映像檔做法是比對安全性修補程式
的
Android 驗證開機程序
(AVB)
AVB 屬性描述元
兩個系統映像檔:Prop: com.android.build.system.security_patch ->
'2019-04-05'
對於未使用 AVB 的裝置,請加入目前系統的安全性修補程式等級
複製到核心 cmdline 或 bootconfig 中,並載入系統啟動載入程式:
androidboot.system.security_patch=2019-04-05
。
硬體需求
當您啟動 DSU 執行個體時,系統會分配兩個暫存檔案:
- 用來儲存
GSI.img
的邏輯分區 (1~1.5 G) - 8 GB 的空白
/data
分區,做為執行 GSI 的沙箱
建議您先保留至少 10 GB 的可用空間,再啟動 DSU 執行個體。此外,DSU 也支援從 SD 卡分配。SD 卡已插入 則屬於分配作業的優先順序最高SD 卡支援: 但對於內部儲存空間可能不足的低階裝置而言,則十分重要。 有 SD 卡時,請勿採用。DSU 不支援 已採用 SD 卡。
可用的前端
您可以使用 adb
、OEM 應用程式或單鍵 DSU 載入器 (位於
Android 11 以上版本)。
使用 ADB 啟動 DSU
如要使用 ADB 啟動 DSU,請輸入以下指令:
$ simg2img out/target/product/.../system.img system.raw
$ gzip -c system.raw > system.raw.gz
$ adb push system.raw.gz /storage/emulated/0/Download
$ adb shell am start-activity \
-n com.android.dynsystem/com.android.dynsystem.VerificationActivity \
-a android.os.image.action.START_INSTALL \
-d file:///storage/emulated/0/Download/system.raw.gz \
--el KEY_SYSTEM_SIZE $(du -b system.raw|cut -f1) \
--el KEY_USERDATA_SIZE 8589934592
使用應用程式啟動 DSU
DSU 的主要進入點是android.os.image.DynamicSystemClient.java
API:
public class DynamicSystemClient {
...
...
/**
* Start installing DynamicSystem from URL with default userdata size.
*
* @param systemUrl A network URL or a file URL to system image.
* @param systemSize size of system image.
*/
public void start(String systemUrl, long systemSize) {
start(systemUrl, systemSize, DEFAULT_USERDATA_SIZE);
}
您必須在裝置上封裝/預先安裝這個應用程式。由於
DynamicSystemClient
是系統 API,您無法透過
SDK API,因此無法在 Google Play 上發布。本應用程式的用途如下:
- 透過供應商定義的配置,擷取圖片清單和對應的網址。
- 將清單中的圖片與裝置進行比對,並顯示相容的圖片 供使用者選取
按照下列方式叫用
DynamicSystemClient.start
:DynamicSystemClient aot = new DynamicSystemClient(...) aot.start( ...URL of the selected image..., ...uncompressed size of the selected image...);
網址會指向一個 gzip 壓縮且未剖析的系統映像檔檔案,您可以 執行下列指令:
$ simg2img ${OUT}/system.img ${OUT}/system.raw
$ gzip ${OUT}/system.raw
$ ls ${OUT}/system.raw.gz
檔案名稱應符合下列格式:
<android version>.<lunch name>.<user defined title>.raw.gz
例如:
o.aosp_taimen-userdebug.2018dev.raw.gz
p.aosp_taimen-userdebug.2018dev.raw.gz
單鍵 DSU 載入器
Android 11 導入了單鍵 DSU 載入器, 是開發人員設定中的前端。
圖 1. 啟動 DSU 載入器
開發人員按一下「DSU 載入器」按鈕時,會擷取預先設定好的 DSU 載入器 網路上的 DSU JSON 描述元,並在 浮動式選單選取映像檔,開始 DSU 安裝作業和進度 會顯示在通知列中。
圖 2. DSU 映像檔安裝進度
根據預設,DSU 載入器會載入包含 GSI 映像檔的 JSON 描述元。 以下章節說明如何製作並載入原始設備製造商 (OEM) 簽署的 DSU 套件 從 DSU 載入器擷取出來
功能旗標
DSU 功能位於 settings_dynamic_android
功能旗標下方。之前
使用 DSU,請務必啟用對應的功能旗標。
圖 3. 啟用功能旗標
在執行使用者版本的裝置上,功能旗標 UI 可能無法使用。於
在此情況下,請改用 adb
指令:
$ adb shell setprop persist.sys.fflag.override.settings_dynamic_system 1
廠商託管於 GCE 的系統映像檔 (選用)
系統映像檔的儲存位置之一是 Compute Engine (GCE) 值區。發布管理員會使用 GCP 儲存空間控制台 新增/刪除/變更發布的系統映像檔
圖片必須開放公開存取,如下所示:
圖 4. GCE 中的公開存取權
如需公開項目的相關程序,請參閱 Google Cloud 說明文件。
ZIP 檔案中多個分區 DSU
從 Android 11 開始,DSU 可以有多個
例如,除了product.img
system.img
。裝置啟動時,第一個階段 init
會偵測
安裝 DSU 分區,並暫時取代裝置端的分區,
已安裝的 DSU 已啟用DSU 套件包含的分區可能含有
裝置上都有對應的分區
圖 5. 包含多個分區的 DSU 程序
原始設備製造商 (OEM) 簽署的 DSU
確保裝置上執行的所有映像檔都經過裝置授權 製造商,就必須簽署 DSU 套件中的所有圖片。例如: 假設有一個 DSU 套件內含兩個分區映像檔,如下所示:
dsu.zip {
- system.img
- product.img
}
system.img
和 product.img
必須先使用 OEM 金鑰簽署
儲存至 ZIP 檔案常見做法是使用非對稱式
演算法,以 RSA 為例,其密鑰是簽署套件,
公開金鑰的用途是驗證金鑰。第一個階段 ramdisk 必須包含
公開金鑰,例如 /avb/*.avbpubkey
。如果裝置已採用 AVB,
現有的簽署程序就能滿足這些需求以下各節將說明
並標明用於設定檔的 AVB pubkey 位置
驗證 DSU 套件中的映像檔
DSU JSON 描述元
DSU JSON 描述元用於描述 DSU 套件。支援兩個原始物件。
首先,include
基本包含額外的 JSON 描述元或重新導向
移到新位置的 DSU 載入器例如:
{
"include": ["https://.../gsi-release/gsi-src.json"]
}
第二,image
基元用於說明已發布的 DSU 套件。內部實景
圖像基元有幾個屬性:
name
和details
屬性是顯示在這裡的字串 供使用者選取的對話方塊cpu_api
、vndk
和os_version
屬性的用途包括 我們將在下一節說明相容性檢查。選用的
pubkey
屬性用於說明公開資訊 金鑰,與用於簽署 DSU 套件的密鑰配對。 指定後,DSU 服務就能檢查裝置是否具有金鑰 用於驗證 DSU 套件這可以避免安裝無法辨識的 DSU 套件,例如安裝 OEM-A 簽署的 DSU 原始設備製造商 (OEM)選用的
tos
屬性指向描述文字檔 服務條款。開發人員 會選取已指定服務條款屬性的 DSU 套件, 對話方塊隨即會開啟,要求開發人員接受條款 才能安裝 DSU 套件圖 6. 服務條款對話方塊
以下是 GSI 的 DSU JSON 描述元供您參考:
{
"images":[
{
"name":"GSI+GMS x86",
"os_version":"10",
"cpu_abi": "x86",
"details":"exp-QP1A.190711.020.C4-5928301",
"vndk":[
27,
28,
29
],
"pubkey":"",
"tos": "https://dl.google.com/developers/android/gsi/gsi-tos.txt",
"uri":"https://.../gsi/gsi_gms_x86-exp-QP1A.190711.020.C4-5928301.zip"
},
{
"name":"GSI+GMS ARM64",
"os_version":"10",
"cpu_abi": "arm64-v8a",
"details":"exp-QP1A.190711.020.C4-5928301",
"vndk":[
27,
28,
29
],
"pubkey":"",
"tos": "https://dl.google.com/developers/android/gsi/gsi-tos.txt",
"uri":"https://.../gsi/gsi_gms_arm64-exp-QP1A.190711.020.C4-5928301.zip"
},
{
"name":"GSI ARM64",
"os_version":"10",
"cpu_abi": "arm64-v8a",
"details":"exp-QP1A.190711.020.C4-5928301",
"vndk":[
27,
28,
29
],
"pubkey":"",
"uri":"https://.../gsi/aosp_arm64-exp-QP1A.190711.020.C4-5928301.zip"
},
{
"name":"GSI x86_64",
"os_version":"10",
"cpu_abi": "x86_64",
"details":"exp-QP1A.190711.020.C4-5928301",
"vndk":[
27,
28,
29
],
"pubkey":"",
"uri":"https://.../gsi/aosp_x86_64-exp-QP1A.190711.020.C4-5928301.zip"
}
]
}
相容性管理
有幾個屬性可用來指定 DSU 套件之間的相容性 和本機裝置:
cpu_api
字串可說明裝置架構。此屬性 是必要項目,而會與ro.product.cpu.abi
系統屬性進行比較。 其值必須完全相符。os_version
是選用整數,用於指定 Android 版本。適用對象 舉例來說,Android 10 的os_version
為10
, Android 11 的os_version
為11
。 當此情況 屬性時,其必須等於或大於ro.system.build.version.release
系統屬性這項檢查是用於避免在 Android 11 上啟動 Android 10 GSI 映像檔 供應商裝置,但目前不支援。允許在 Android 10 裝置上啟動 Android 11 GSI 映像檔。vndk
是選用的陣列,用於指定包含在 DSU 套件如果有指定的話,DSU 載入程式會檢查該數字是否 從ro.vndk.version
系統屬性擷取而來。
基於安全考量,撤銷 DSU 金鑰
在極少數的情況下,用於簽署 DSU 圖像的 RSA 金鑰組 則應盡快更新 ramdisk 程序,以移除 遭盜用的金鑰。除了更新啟動分區外, 透過 HTTPS 的 DSU 金鑰撤銷清單 (索引鍵黑名單) 成功入侵的金鑰 網址。
DSU 金鑰撤銷清單包含已撤銷的 AVB 公開金鑰。 在 DSU 安裝期間,系統會驗證 DSU 映像檔中的公開金鑰 與撤銷清單互動如果發現圖片中含有已撤銷的公開 金鑰,則 DSU 安裝程序會停止。
金鑰撤銷清單的網址是 HTTPS 網址,以便確保安全性 會在資源字串中指定:
frameworks/base/packages/DynamicSystemInstallationService/res/values/strings.xml@key_revocation_list_url
字串的值是
https://dl.google.com/developers/android/gsi/gsi-keyblacklist.json
,也就是
Google 發布 GSI 金鑰的撤銷清單。這個資源字串可以是
讓採用 DSU 功能的原始設備製造商
自己的索引鍵黑名單這可讓原始設備製造商 (OEM) 封鎖
而非更新裝置的 ramdisk 映像檔。
撤銷清單的格式如下:
{
"entries":[
{
"public_key":"bf14e439d1acf231095c4109f94f00fc473148e6",
"status":"REVOKED",
"reason":"Key revocation test key"
},
{
"public_key":"d199b2f29f3dc224cca778a7544ea89470cbef46",
"status":"REVOKED",
"reason":"Key revocation test key"
}
]
}
public_key
是已撤銷金鑰的 SHA-1 摘要,格式如下: 產生 AVB pubkey 專區。status
表示金鑰的撤銷狀態。目前 支援的值為REVOKED
。reason
是選用字串,用來說明撤銷原因。
DSU 程序
本節說明如何執行多項 DSU 設定程序。
產生新的金鑰組
使用 openssl
指令在 .pem
中產生 RSA 私密/公開金鑰組
格式 (例如大小為 2048 位元):
$ openssl genrsa -out oem_cert_pri.pem 2048
$ openssl rsa -in oem_cert_pri.pem -pubout -out oem_cert_pub.pem
私密金鑰可能無法存取,只會保存在 硬體安全性模組 (HSM)。 在這種情況下,金鑰會在金鑰後方提供 x509 公用金鑰憑證 。請參閱將配對 pubkey 新增至 ramdisk 一節。 一節,瞭解如何從 x509 憑證產生 AVB 公開金鑰。
如何將 x509 憑證轉換為 PEM 格式:
$ openssl x509 -pubkey -noout -in oem_cert_pub.x509.pem > oem_cert_pub.pem
如果憑證已經是 PEM 檔案,請略過這個步驟。
將配對 pubkey 新增至 ramdisk
oem_cert.avbpubkey
必須放在 /avb/*.avbpubkey
底下,才能驗證
已簽署的 DSU 套件。首先,將 PEM 格式的公開金鑰轉換為 AVB 公開金鑰
金鑰格式:
$ avbtool extract_public_key --key oem_cert_pub.pem --output oem_cert.avbpubkey
接著,請按照下列步驟,在第一個階段 ramdisk 中加入公開金鑰。
新增預先建構的模組來複製
avbpubkey
。舉例來說,將 「device/<company>/<board>/oem_cert.avbpubkey
」和device/<company>/<board>/avb/Android.mk
,內容如下:include $(CLEAR_VARS) LOCAL_MODULE := oem_cert.avbpubkey LOCAL_MODULE_CLASS := ETC LOCAL_SRC_FILES := $(LOCAL_MODULE) ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true) LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/first_stage_ramdisk/avb else LOCAL_MODULE_PATH := $(TARGET_RAMDISK_OUT)/avb endif include $(BUILD_PREBUILT)
將 droidcore 目標設為依附於新增的
oem_cert.avbpubkey
:droidcore: oem_cert.avbpubkey
在 JSON 描述元中產生 AVB pubkey 屬性
oem_cert.avbpubkey
為 AVB 公開金鑰二進位格式。使用 SHA-1 即可
將其轉換為 JSON 描述元前的可讀性:
$ sha1sum oem_cert.avbpubkey | cut -f1 -d ' '
3e62f2be9d9d813ef5........866ac72a51fd20
這會是 JSON 描述元的 pubkey
屬性內容。
"images":[
{
...
"pubkey":"3e62f2be9d9d813ef5........866ac72a51fd20",
...
},
簽署 DSU 套件
請透過下列其中一種方法簽署 DSU 套件:
方法 1:重複使用原始 AVB 簽署程序產生的成果, 建立 DSU 套件另一種方法是擷取已簽名的 ,然後使用擷取的圖片建立 ZIP 檔案 檔案。
方法 2:使用下列指令簽署 DSU 分區 (如有) 可用的金鑰。DSU 套件 (ZIP 檔案) 中的每個
img
都會經過簽署 分別:$ key_len=$(openssl rsa -in oem_cert_pri.pem -text | grep Private-Key | sed -e 's/.*(\(.*\) bit.*/\1/') $ for partition in system product; do avbtool add_hashtree_footer \ --image ${OUT}/${partition}.img \ --partition_name ${partition} \ --algorithm SHA256_RSA${key_len} \ --key oem_cert_pri.pem done
如要進一步瞭解如何使用 avbtool
新增 add_hashtree_footer
,請參閱
使用 avbtool。
在本機驗證 DSU 套件
建議你針對與以下配對公開金鑰的配對公開金鑰,驗證所有本機映像檔: 這些指令:
for partition in system product; do
avbtool verify_image --image ${OUT}/${partition}.img --key oem_cert_pub.pem
done
預期的輸出內容如下所示:
Verifying image dsu/system.img using key at oem_cert_pub.pem
vbmeta: Successfully verified footer and SHA256_RSA2048 vbmeta struct in dsu/system.img
: Successfully verified sha1 hashtree of dsu/system.img for image of 898494464 bytes
Verifying image dsu/product.img using key at oem_cert_pub.pem
vbmeta: Successfully verified footer and SHA256_RSA2048 vbmeta struct in dsu/product.img
: Successfully verified sha1 hashtree of dsu/product.img for image of 905830400 bytes
建立 DSU 套件
以下範例會建立一個包含 system.img
和
product.img
:
dsu.zip {
- system.img
- product.img
}
兩個映像檔都簽署完成後,請使用以下指令建立 ZIP 檔案:
$ mkdir -p dsu
$ cp ${OUT}/system.img dsu
$ cp ${OUT}/product.img dsu
$ cd dsu && zip ../dsu.zip *.img && cd -
自訂單鍵 DSU
根據預設,DSU 載入器會指向 GSI 映像檔的中繼資料
https://...google.com/.../gsi-src.json
。
原始設備製造商 (OEM) 可定義 persist.sys.fflag.override.settings_dynamic_system.list
來覆寫清單
屬性。舉例來說,原始設備製造商 (OEM) 可能會
提供 JSON 中繼資料,其中包含 GSI 以及原始設備製造商 (OEM) 專屬映像檔,如下所示:
{
"include": ["https://dl.google.com/.../gsi-src.JSON"]
"images":[
{
"name":"OEM image",
"os_version":"10",
"cpu_abi": "arm64-v8a",
"details":"...",
"vndk":[
27,
28,
29
],
"spl":"...",
"pubkey":"",
"uri":"https://.../....zip"
},
}
如圖 7 所示,原始設備製造商 (OEM) 可鏈結已發布的 DSU 中繼資料。
圖 7. 鏈結已發布的 DSU 中繼資料