Google is committed to advancing racial equity for Black communities. See how.
本頁面由 Cloud Translation API 翻譯而成。
Switch to English

動態系統更新

動態系統更新(DSU)允許您製作一個Android系統映像,用戶可以從互聯網上下載該映像並進行嘗試,而不會破壞當前的系統映像。本文檔介紹瞭如何支持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:
    • 109s,8G用戶,867M系統,文件系統類型:F2FS:encryption = aes-256-xts:aes-256-cts
    • 104s,8G用戶,867M系統,文件系統類型:F2FS:encryption = ice
  • 使用ext4:
    • 135s,8G用戶,867M系統,文件系統類型:ext4:加密= aes-256-xts:aes-256-cts

如果在您的平台上花費的時間更長,則可能需要檢查mount標誌是否包含任何使“ sync”寫入的標誌,或者您可以顯式指定“ async”標誌以獲得更好的性能。

需要metadata分區(16 MB或更大)來存儲與已安裝圖像有關的數據。必須在第一階段安裝期間安裝它。

userdata的分區必須使用F2FS或ext4文件系統。使用F2FS時,請包括Android通用內核中所有可用的F2FS相關補丁。

DSU是使用內核/通用4.9開發和測試的。建議為此功能使用內核4.9或更高版本。

供應商HAL行為

韋弗·哈爾

Weaver HAL提供固定數量的插槽,用於存儲用戶密鑰。 DSU佔用兩個額外的鍵槽。如果OEM具有Weaver HAL,則它需要具有足夠的插槽來容納通用系統映像(GSI)和主機映像。

關守HAL

Gatekeeper HAL需要支持較大的USER_ID值,因為GSI將UID偏移到HAL +1000000。

驗證啟動

如果要支持在鎖定狀態下引導Developer GSI映像而不禁用已驗證的引導,請通過在文件device/<device_name>/device.mk文件中添加以下行來包含Developer GSI密鑰:

$(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中: androidboot.system.security_patch=2019-04-05

硬件要求

啟動DSU實例時,將分配兩個臨時文件:

  • 用於存儲GSI.imgGSI.img G)的邏輯分區
  • 8 GB空/data分區作為運行GSI的沙箱

我們建議在啟動DSU實例之前至少保留10 GB的可用空間。 DSU還支持從SD卡進行分配。如果有SD卡,則分配的優先級最高。對於可能沒有足夠內部存儲器的低功耗設備,SD卡支持至關重要。當SD卡存在,確保它沒有被採納。 DSU不支持採用的SD卡

可用的前端

您可以使用adb ,OEM應用程序或一鍵式DSU加載器(在Android 11或更高版本中)啟動DSU。

使用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上發布該應用程序。這個程序的目的是:

  1. 使用供應商定義的方案獲取圖像列表和相應的URL。
  2. 將列表中的圖像與設備進行匹配,並顯示兼容圖像供用戶選擇。
  3. 像這樣調用DynamicSystemClient.start

    DynamicSystemClient aot = new DynamicSystemClient(...)
       aot.start(
            ...URL of the selected image...,
            ...uncompressed size of the selected image...);
    
    

該URL指向一個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加載程序,它是開發人員設置中的前端。

啟動DSU加載器

圖1.啟動DSU加載器

當開發人員單擊DSU加載程序按鈕時,它將從Web上獲取預配置的DSU JSON描述符,並在浮動菜單中顯示所有適用的圖像。選擇一個映像以開始DSU安裝,進度將顯示在通知欄上。

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上的供應商主機系統映像(可選)

系統映像的可能存儲位置之一是Google Compute Engine(GCE)存儲桶。發布管理員使用GCP存儲控制台添加/刪除/更改發布的系統映像。

圖像必須是公共訪問權限,如下所示:

GCE中的公共訪問

圖4. GCE中的公共訪問

Google Cloud文檔中提供了公開項目的過程。

ZIP文件中的多分區DSU

從Android 11開始,DSU可以具有多個分區。例如,除了system.img之外,它還可以包含product.img 。設備啟動時,第一階段init會在啟用安裝的DSU的情況下檢測已安裝的DSU分區並臨時替換設備上的分區。 DSU程序包可能包含一個分區,該分區在設備上沒有相應的分區。

具有多個分區的DSU進程

圖5.具有多個分區的DSU流程

OEM簽名的DSU

為確保在設備上運行的所有映像均得到設備製造商的授權,必須對DSU軟件包中的所有映像進行簽名。例如,假定有一個DSU包,其中包含兩個分區映像,如下所示:

dsu.zip {
    - system.img
    - product.img
}

必須先使用OEM密鑰對system.imgproduct.img進行簽名,然後再將它們放入ZIP文件。常見的做法是使用非對稱算法,例如RSA,其中使用秘密密鑰對軟件包進行簽名,並使用公共密鑰進行驗證。第一階段ramdisk必須包含配對的公用密鑰,例如/avb/*.avbpubkey 。如果設備已經採用了AVB,則現有的簽名過程就足夠了。以下各節說明了簽名過程,並突出顯示了用於驗證DSU包中的圖像的AVB pubkey的位置。

DSU JSON描述符

DSU JSON描述符描述了DSU包。它支持兩個原語。首先, include原語包含其他JSON描述符,或將DSU加載程序重定向到新位置。例如:

{
    "include": ["https://.../gsi-release/gsi-src.json"]
}

其次, image原語用於描述已發布的DSU軟件包。在圖像基元內部有幾個屬性:

  • namedetails屬性是顯示在對話框上的字符串,供用戶選擇。

  • cpu_apivndkos_version屬性用於兼容性檢查,這將在下一部分中介紹。

  • 可選的pubkey屬性描述與用於簽名DSU程序包的秘密密鑰配對的公共密鑰。指定後,DSU服務可以檢查設備是否具有用於驗證DSU軟件包的密鑰。這樣可以避免安裝無法識別的DSU軟件包,例如,將由OEM-A簽名的DSU安裝到OEM-B製造的設備上。

  • 可選的tos屬性指向一個文本文件,該文件描述了相應DSU軟件包的服務條款。當開發人員選擇指定了服務條款屬性的DSU軟件包時,將打開圖6所示的對話框,要求開發人員在安裝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_version10 ,對於Android 11, os_version11 。指定此屬性後,它必須等於或大於ro.system.build.version.release系統屬性。此檢查用於防止在當前不支持的Android 11供應商設備上引導Android 10 GSI映像。引導一個Android 10裝置在Android 11 GSI圖像是允許的。

  • vndk是一個可選數組,用於指定DSU軟件包中包括的所有VNDK。指定後,DSU加載程序將檢查是否包括從ro.vndk.version系統屬性中提取的數字。

吊銷DSU密鑰以確保安全

在極少數情況下,用於簽名DSU映像的RSA密鑰對受到破壞時,應盡快更新虛擬磁盤以刪除受到破壞的密鑰。除了更新引導分區之外,您還可以使用HTTPS URL中的DSU密鑰吊銷列表(密鑰黑名單)來阻止洩露的密鑰。

DSU密鑰吊銷列表包含已吊銷的AVB公鑰的列表。在DSU安裝期間,DSU映像內的公鑰將通過吊銷列表進行驗證。如果發現映像包含已撤消的公鑰,則DSU安裝過程將停止。

密鑰吊銷列表URL應該是HTTPS URL,以確保安全性,並在資源字符串中指定:

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可以提供並維護自己的密鑰黑名單。這為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是描述撤銷reason的可選字符串。

DSU程序

本節介紹如何執行幾個DSU配置過程。

生成新的密鑰對

使用openssl命令以.pem格式(例如,大小為2048位)生成RSA私鑰/公鑰對:

$ openssl genrsa -out oem_cert_pri.pem 2048
$ openssl rsa -in oem_cert_pri.pem -pubout -out oem_cert_pub.pem

私鑰可能無法訪問,只能保存在硬件安全模塊(HSM)中。在這種情況下,密鑰生成後可能會有x509公共密鑰證書可用。有關從x509證書生成AVB公鑰的說明,請參閱將配對公鑰添加到ramdisk部分。

要將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中。

  1. 添加一個預構建模塊以復制avbpubkey 。例如,添加具有以下內容的device/<company>/<board>/oem_cert.avbpubkeydevice/<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)
    
  2. 使droidcore目標依賴於添加的oem_cert.avbpubkey

    droidcore: oem_cert.avbpubkey
    

在JSON描述符中生成AVB pubkey屬性

oem_cert.avbpubkey採用AVB公鑰二進制格式。在將其放入JSON描述符之前,使用SHA-1使其可讀:

$ 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包裹

以下示例製作了一個DSU包,其中包含system.imgproduct.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可以通過定義指向其自己的JSON描述符的persist.sys.fflag.override.settings_dynamic_system.list屬性來覆蓋該列表。例如,OEM可以提供包括GSI以及以下類似的OEM專有映像的JSON元數據:

{
    "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"
      },

}

OEM可以鏈接發布的DSU元數據,如圖7所示。

鏈接已發布的DSU元數據

圖7.鏈接發布的DSU元數據