Dynamic System Updates(DSU)により、Android システム イメージを作成できます。ユーザーはこれをインターネットからダウンロードして、現在のシステム イメージの破損を心配せずに試すことができます。このドキュメントでは、DSU をサポートする方法について説明します。
カーネルの要件
カーネルの要件については、動的パーティションの実装をご覧ください。
また、DSU は Android システム イメージを認証するために、device-mapper-verity(dm-verity)カーネル機能も使用します。したがって、次のカーネル構成を有効にする必要があります。
CONFIG_DM_VERITY=y
CONFIG_DM_VERITY_FEC=y
パーティションの要件
Android 11 以降、DSU では F2FS または ext4 ファイル システムを使用するために /data
パーティションが必要になりました。F2FS のほうがパフォーマンスが高速なのでこちらが推奨されますが、違いはそれほど大きくありません。
Google Pixel デバイスで DSU にかかる時間の例を以下に示します。
- F2FS を使用する場合:
- 109s、8G ユーザー、867M システム、ファイル システムのタイプ: F2FS: encryption=aes-256-xts:aes-256-cts
- 104s、8G ユーザー、867M システム、ファイル システムのタイプ: F2FS: encryption=ice
- ext4 を使用する場合:
- 135s、8G ユーザー、867M システム、ファイル システムのタイプ: ext4: encryption=aes-256-xts:aes-256-cts
使用しているプラットフォームでこれより時間がかかる場合は、マウントフラグに「sync」書き込みを行うフラグが含まれていないかをチェックしてください。また、パフォーマンスを改善するために「async」フラグを明示的に指定する方法もあります。
インストールされたイメージに関連するデータを保存するには、metadata
パーティション(16 MB 以上)が必要です。このパーティションは、第 1 ステージの mount の際にマウントする必要があります。
userdata
パーティションでは、F2FS または ext4 ファイル システムを使用する必要があります。F2FS を使用する場合は、Android 共通カーネルに記載されている利用可能な F2FS 関連のパッチをすべて適用します。
DSU は kernel/common 4.9 で開発およびテストされました。この機能では、kernel 4.9 以降の使用が推奨されます。
ベンダー HAL の動作
Weaver HAL
Weaver HAL は、ユーザーキーを格納するための固定数のスロットを提供します。DSU は、追加で 2 つのキースロットを使用します。OEM が Weaver HAL を提供する場合、汎用システム イメージ(GSI)とホストイメージ用に十分なスロットが必要です。
Gatekeeper HAL
Gatekeeper HAL は、大きな USER_ID
値をサポートする必要があります。これは、GSI が HAL に対して UID を +1,000,000 だけオフセットするためです。
確認付きブート
確認付きブートを無効にせずにロックされた状態のデベロッパー GSI イメージを起動できるようにするには、device/<device_name>/device.mk
ファイルに次の行を追加して、デベロッパー GSI キーを組み込みます。
$(call inherit-product, $(SRC_TARGET_DIR)/product/developer_gsi_keys.mk)
ロールバック保護
DSU を使用する場合、ダウンロードされた Android システム イメージが、デバイス上の現在のシステム イメージより新しい必要があります。これを確認するには、両方のシステム イメージの Android Verified Boot(AVB)の AVB プロパティ記述子に含まれているセキュリティ パッチ レベルを比較します。例: Prop: com.android.build.system.security_patch ->
'2019-04-05'
AVB を使用していないデバイスの場合は、現在のシステム イメージのセキュリティ パッチ レベルをブートローダーでカーネルの cmdline または bootconfig に指定します。例: androidboot.system.security_patch=2019-04-05
ハードウェアの要件
DSU インスタンスを起動すると、次の 2 つの一時ファイルが割り当てられます。
GSI.img
(1~1.5 G)を格納する論理パーティション- 8 GB の空の
/data
パーティション(GSI を実行するためのサンドボックスとして使用)
DSU インスタンスを起動する前に、10 GB 以上の空き領域を確保することをおすすめします。DSU は SD カードからの割り当てもサポートします。SD カードが存在する場合、割り当ての優先度が最も高くなります。内部ストレージが十分にない低容量デバイスでは、SD カードのサポートが不可欠です。SD カードがある場合は、内部ストレージ化されていないことを確認します。DSU では、内部ストレージ化された SD カードはサポートされていません。
使用可能なフロントエンド
DSU は、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 でアプリを公開できません。このアプリの目的は次のとおりです。
- ベンダー定義のスキームを使用して、イメージリストおよび対応する URL を取得する。
- リスト内のイメージをデバイスと照合し、ユーザーによる選択が可能な互換性のあるイメージを表示する。
次のように
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 ローダが導入されました。
図 1. 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 上のベンダーホスト システム イメージ(オプション)
システム イメージを格納できる場所の 1 つに、Google Compute Engine(GCE)バケットがあります。リリース管理者は、GCP ストレージ コンソールを使用して、リリースされたシステム イメージを追加、削除、変更します。
イメージは次のように公開アクセスである必要があります。
図 4. GCE での公開アクセス
アイテムを一般公開する手順については、Google Cloud ドキュメントをご覧ください。
ZIP ファイル内のマルチパーティション DSU
Android 11 以降では、DSU に複数のパーティションを設定できます。たとえば、system.img
に加えて product.img
を設定できます。デバイスが起動されると、第 1 ステージの init
によって、インストール済みの DSU パーティションが検出され、インストール済みの DSU が有効化されたときにデバイス上のパーティションが一時的に置き換えられます。DSU パッケージには、対応するパーティションがデバイス上にないパーティションが含まれている場合があります。
図 5. 複数のパーティションを持つ DSU プロセス
OEM 署名付きの DSU
デバイスで実行されているすべてのイメージがデバイス メーカーにより認証済みであることを保証するには、DSU パッケージ内のすべてのイメージに署名する必要があります。たとえば、DSU パッケージに次の 2 つのパーティション イメージが含まれているとします。
dsu.zip {
- system.img
- product.img
}
ZIP ファイルに圧縮する前に、system.img
と product.img
の両方を OEM 鍵で署名する必要があります。その場合、一般的には RSA などの非対称アルゴリズムを使用します。たとえば、パッケージの署名に秘密鍵を使用し、認証に公開鍵を使用します。第 1 ステージの RAM ディスクには、ペア設定された公開鍵(/avb/*.avbpubkey
など)を含める必要があります。デバイスに AVB がすでに導入されている場合は、既存の署名手順で十分です。以下のセクションでは、DSU パッケージ内のイメージの認証に使用する AVB 公開鍵の配置に重点を置いて、署名プロセスについて説明します。
DSU JSON 記述子
DSU JSON 記述子は、DSU パッケージを記述します。2 つのプリミティブがサポートされています。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-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_version
は10
です。Android 11 の場合、os_version
は11
です。この属性を指定する場合は、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 鍵ペアが不正使用されることがあります。その場合、可能な限り早急に RAM ディスクを更新して、不正使用された鍵を削除する必要があります。ブート パーティションを更新したうえで、さらに DSU 鍵の取り消しリスト(鍵ブラックリスト)を使用して HTTPS URL から不正使用された鍵をブロックします。
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 はデバイスの RAM ディスク イメージを更新しなくても、特定の公開鍵をブロックできます。
取り消しリストの形式は次のとおりです。
{
"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 公開鍵を生成するに記載されている形式で指定します。status
は、鍵の取り消しステータスを示します。現在サポートされている値はREVOKED
のみです。reason
はオプションで、取り消し理由を記述する文字列です。
DSU の構成手順
このセクションでは、DSU の構成手順について説明します。
新しい鍵ペアを生成する
openssl
コマンドを使用して、.pem
形式の RSA 秘密鍵 / 公開鍵ペア(たとえば、2,048 ビットのサイズ)を生成します。
$ 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 公開鍵を生成する手順については、RAM ディスクにペア設定公開鍵を追加するをご覧ください。
x509 証明書を PEM 形式に変換する方法は次のとおりです。
$ openssl x509 -pubkey -noout -in oem_cert_pub.x509.pem > oem_cert_pub.pem
証明書がすでに PEM ファイルである場合は、この手順をスキップしてください。
RAM ディスクにペア設定公開鍵を追加する
署名付きの DSU パッケージを認証するには、oem_cert.avbpubkey
を /avb/*.avbpubkey
に配置する必要があります。まず、PEM 形式の公開鍵を AVB 公開鍵形式に変換します。
$ avbtool extract_public_key --key oem_cert_pub.pem --output oem_cert.avbpubkey
次に、下記の手順に沿って、第 1 ステージの RAM ディスクに公開鍵を追加します。
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 公開鍵属性を生成する
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 パッケージを作成します。
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
プロパティを定義することにより、リストを上書きできます。たとえば、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 は、図 7 に示すように、公開されている DSU メタデータのチェーンを作成できます。
図 7. 公開されている DSU メタデータのチェーンを作成する