新しいデバイスに仮想A / Bを実装する、または起動したデバイスを後付けするには、デバイス固有のコードを変更する必要があります。
ビルドフラグ
仮想A / Bを使用するデバイスは、A / Bデバイスとして構成し、動的パーティションで起動する必要があります。
仮想A / Bで起動するデバイスの場合、仮想A / Bデバイスの基本構成を継承するようにデバイスを設定します。
$(call inherit-product, \
$(SRC_TARGET_DIR)/product/virtual_ab_ota.mk)
仮想A / Bで起動するデバイスは、Bスロットがスーパーではなくなったため、 BOARD_SUPER_PARTITION_SIZE
のボードサイズの半分しか必要としません。つまり、 BOARD_SUPER_PARTITION_SIZE
は、 sum(更新グループのサイズ)+オーバーヘッド以上である必要があります。これは、 sum(パーティションのサイズ)+オーバーヘッド以上である必要があります。
仮想A / Bで圧縮スナップショットを有効にするには、代わりに次の基本構成を継承します。
$(call inherit-product, \
$(SRC_TARGET_DIR)/product/virtual_ab_ota/compression.mk)
ブート制御HAL
ブート制御HALは、OTAクライアントがブートスロットを制御するためのインターフェイスを提供します。仮想A / Bでは、フラッシュ/ファクトリリセット中にブートローダーを確実に保護するために追加のAPIが必要になるため、ブートコントロールHALのマイナーバージョンアップグレードが必要です。 HAL定義の最新バージョンについては、 IBootControl.halおよびtypes.halを参照してください。
// hardware/interfaces/boot/1.1/types.hal
enum MergeStatus : uint8_t {
NONE, UNKNOWN, SNAPSHOTTED, MERGING, CANCELLED };
// hardware/interfaces/boot/1.1/IBootControl.hal
package android.hardware.boot@1.1;
interface IBootControl extends @1.0::IBootControl {
setSnapshotMergeStatus(MergeStatus status)
generates (bool success);
getSnapshotMergeStatus()
generates (MergeStatus status);
}
// Recommended implementation
Return<bool> BootControl::setSnapshotMergeStatus(MergeStatus v) {
// Write value to persistent storage
// e.g. misc partition (using libbootloader_message)
// bootloader rejects wipe when status is SNAPSHOTTED
// or MERGING
}
Fstabの変更
メタデータパーティションの整合性は、特にOTA更新が適用された直後のブートプロセスに不可欠です。したがって、メタデータパーティションは、 first_stage_init
がマウントする前にチェックする必要があります。これを確実に行うには、 check
fs_mgrフラグを/metadata
のエントリに追加します。以下に例を示します。
/dev/block/by-name/metadata /metadata ext4 noatime,nosuid,nodev,discard,sync wait,formattable,first_stage_mount,check
カーネル要件
スナップショットを有効にするには、 CONFIG_DM_SNAPSHOT
をtrue
に設定します。
F2FSを使用するデバイスの場合は、f2fsを含めます。FS_NOCOW_FLフラグをユーザーカーネルパッチにエクスポートして、ファイルの固定を修正します。 f2fsを含めます:整列された固定ファイルカーネルパッチもサポートします。
仮想A / Bは、カーネルバージョン4.3で追加された機能( snapshot
およびsnapshot-merge
ターゲットのオーバーフローステータスビット)に依存しています。 Android 9以降で起動するすべてのデバイスには、カーネルバージョン4.4以降がすでに搭載されている必要があります。
圧縮されたスナップショットを有効にするために、サポートされる最小のカーネルバージョンは4.19です。 CONFIG_DM_USER=m
またはCONFIG_DM_USER=y
を設定します。前者(モジュール)を使用する場合は、モジュールを第1ステージのRAMディスクにロードする必要があります。これは、デバイスのMakefileに次の行を追加することで実現できます。
BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD := dm-user.ko
Android11にアップグレードするデバイスに後付け
Android 11にアップグレードする場合、動的パーティションで起動したデバイスは、オプションで仮想A / Bを後付けできます。更新プロセスは、仮想A / Bで起動するデバイスの場合とほとんど同じですが、いくつかの小さな違いがあります。
COWファイルの場所—起動デバイスの場合、OTAクライアントは、
/data
内のスペースを使用する前に、スーパーパーティション内の使用可能なすべての空のスペースを使用します。レトロフィットデバイスの場合、スーパーパーティションには常に十分なスペースがあるため、COWファイルが/data
に作成されることはありません。ビルド時機能フラグ—仮想A / Bを後付けするデバイスの場合、以下に示すように、
PRODUCT_VIRTUAL_AB_OTA
とPRODUCT_VIRTUAL_AB_OTA_RETROFIT
の両方がtrue
に設定されます。(call inherit-product, \
(SRC_TARGET_DIR)/product/virtual_ab_ota_retrofit.mk)
スーパーパーティションサイズ—仮想A / Bで起動するデバイスは、Bスロットがスーパーパーティションにないため、
BOARD_SUPER_PARTITION_SIZE
を半分に削減できます。仮想A / Bを後付けするデバイスは、古いスーパーパーティションサイズを保持するため、BOARD_SUPER_PARTITION_SIZE
は2 * sum(更新グループのサイズ)+オーバーヘッド以上であり、 2 * sum(パーティションのサイズ)以上です。 +オーバーヘッド。
ブートローダーの変更
更新のマージステップ中、 /data
はAndroidOSの唯一のインスタンス全体を保持します。移行が開始されると、コピーが完了するまで、ネイティブsystem
、 vendor
、およびproduct
のパーティションは不完全になります。このプロセス中に、リカバリまたは[システム設定]ダイアログを介してデバイスが工場出荷時にリセットされた場合、デバイスは起動できなくなります。
/data
を消去する前に、デバイスの状態に応じて、リカバリまたはロールバックでマージを終了します。
- 以前に新しいビルドが正常に起動した場合は、移行を終了します。
- それ以外の場合は、古いスロットにロールバックします。
- 動的パーティションの場合は、前の状態にロールバックします。
- 静的パーティションの場合、アクティブスロットを古いスロットに設定します。
デバイスのロックが解除されている場合、ブートローダーとfastbootd
の両方が/data
パーティションを消去できます。 fastbootd
は移行を強制的に完了することができますが、ブートローダーはできません。ブートローダーは、マージが進行中であるかどうか、または/data
内のどのブロックがOSパーティションを構成しているかを知りません。デバイスは、次の手順を実行して、ユーザーが無意識のうちにデバイスを操作不能(ブリック)にしないようにする必要があります。
- ブートローダーが
setSnapshotMergeStatus()
メソッドによって設定された値を読み取れるように、ブート制御HALを実装します。 - マージステータスが
MERGING
の場合、またはマージステータスがSNAPSHOTTED
であり、スロットが新しく更新されたスロットに変更された場合、ユーザーuserdata
、metadata
、またはマージステータスを格納するパーティションをワイプする要求はブートローダーで拒否する必要があります。 -
fastboot snapshot-update cancel
コマンドを実装して、ユーザーがこの保護メカニズムをバイパスすることをブートローダーに通知できるようにします。 - カスタムフラッシュツールまたはスクリプトを変更して、デバイス全体をフラッシュするときに
fastboot snapshot-update cancel
を発行します。デバイス全体をフラッシュするとOTAが削除されるため、これは安全に発行できます。ツールは、fastboot getvar snapshot-update-status
を実装することにより、実行時にこのコマンドを検出できます。このコマンドは、エラー状態を区別するのに役立ちます。
例
struct VirtualAbState {
uint8_t StructVersion;
uint8_t MergeStatus;
uint8_t SourceSlot;
};
bool ShouldPreventUserdataWipe() {
VirtualAbState state;
if (!ReadVirtualAbState(&state)) ...
return state.MergeStatus == MergeStatus::MERGING ||
(state.MergeStatus == MergeStatus::SNAPSHOTTED &&
state.SourceSlot != CurrentSlot()));
}
Fastbootツールの変更
Android 11は、fastbootプロトコルに次の変更を加えます。
-
getvar snapshot-update-status
—ブートコントロールHALがブートローダーに通信した値を返します。- 状態が
MERGING
の場合、ブートローダーはmerging
を返す必要があります。 - 状態が
SNAPSHOTTED
の場合、ブートローダーはsnapshotted
を返す必要があります。 - それ以外の場合、ブートローダーは
none
を返す必要があります。
- 状態が
-
snapshot-update merge
—マージ操作を完了し、必要に応じてrecovery / fastbootdで起動します。このコマンドは、snapshot-update-status
がmerging
されている場合にのみ有効であり、fastbootdでのみサポートされます。 -
snapshot-update cancel
—ブートコントロールHALのマージステータスをCANCELLED
に設定します。デバイスがロックされている場合、このコマンドは無効です。 -
erase
またはwipe
—metadata
データ、ユーザーuserdata
、またはブートコントロールHALのマージステータスを保持しているパーティションのerase
またはwipe
は、スナップショットのマージステータスを確認する必要があります。ステータスがMERGING
またはSNAPSHOTTED
の場合、デバイスは操作を中止する必要があります。 -
set_active
—アクティブスロットを変更するset_active
コマンドは、スナップショットマージステータスをチェックする必要があります。ステータスがMERGING
の場合、デバイスは操作を中止する必要があります。SNAPSHOTTED
状態でスロットを安全に交換できます。
これらの変更は、誤ってデバイスを起動できなくすることを防ぐように設計されていますが、自動化されたツールを混乱させる可能性があります。 fastboot flashall
の実行など、コマンドをすべてのパーティションのフラッシュのコンポーネントとして使用する場合は、次のフローを使用することをお勧めします。
-
getvar snapshot-update-status
照会します。 -
merging
またはsnapshotted
を作成する場合は、snapshot-update cancel
updatecancelを発行します。 - 点滅する手順に進みます。
ストレージ要件の削減
スーパーでフルA / Bストレージが割り当てられておらず、必要に応じて/data
を使用することが予想されるデバイスでは、ブロックマッピングツールを使用することを強くお勧めします。ブロックマッピングツールは、ビルド間でブロック割り当ての一貫性を維持し、スナップショットへの不要な書き込みを減らします。これは、 OTAサイズの削減に記載されています。