仮想 A/B の実装 - パッチ

以下のパッチを選択して、既知の問題に対処してください。

サイドローディング時に割り当て可能なスペースを正しくチェックする

サイズが 2 × アップデート グループのサイズ合計よりも小さい super パーティションの仮想 A/B デバイスでフル OTA パッケージをサイドローディングした場合、リカバリログ /tmp/recovery.log に次のように記載され、失敗します。

The maximum size of all groups with suffix _b (...) has exceeded half of allocatable space for dynamic partitions ...

以下に、ログの例を示します。

[INFO:dynamic_partition_control_android.cc(1020)] Will overwrite existing partitions. Slot A may be unbootable until update finishes!
[...]
[ERROR:dynamic_partition_control_android.cc(803)] The maximum size of all groups with suffix _b (2147483648) has exceeded half of allocatable space for dynamic partitions 1073741824.

この問題が発生した場合は、CL 1399393 を選択し、デバイスが boot パーティションとして recovery パーティションを使用していない場合は、boot パーティションまたは recovery パーティションを再ビルドしてフラッシュします。

マージ中のセグメンテーション違反を修正する

OTA アップデートを適用した後、VAB のマージの処理中に update_engine_client --cancel を呼び出すと、CleanupPreviousUpdateAction がクラッシュします。markSlotSuccessful が遅延すると、ワイルド ポインタのエラーが発生する可能性もあります。

これは、StopActionInternal 関数の追加によって解決されました。CleanupPreviousUpdateAction は破棄の際に保留中のタスクをキャンセルします。メッセージ ループ内で保留中のタスクのタスク ID を追跡する変数は維持されます。破棄の際は、セグメンテーション違反の発生を防ぐために、保留中のタスクがキャンセルされます。

マージ中に発生する update_engine での SIGSEGV のクラッシュを修正するには、Android 11 ソースツリーで次の変更を適用します。

  • CL 1439792(CL 1439372 の前提条件)
  • CL 1439372CleanupPreviousUpdateAction: 破棄の際の保留中のタスクのキャンセル)
  • CL 1663460markSlotSuccessful が遅れた場合の潜在的なワイルド ポインタのエラーの修正)

VAB の誤ったスロットの切り替えを修正する(OTA アップデート後)

Android 11 以降では、OTA アップデート後にデバイスでのスロットの切り替えを同期しないと、デバイスが使用不能な状態になる可能性があります。IBootControl HAL のスロット切り替えの実装で書き込みが実行される場合は、その書き込みを直ちにフラッシュする必要があります。書き込みがフラッシュされず、マージの開始後、ハードウェアがスロットの切り替えの書き込みをフラッシュできる前にデバイスを再起動した場合、デバイスが前のスロットに戻されて起動できない場合があります。

コード ソリューションの例については、CL 1535570 をご覧ください。

update_engine による早すぎるマージを防ぐ

デバイスが起動され(Android 11 以降)、起動が完了すると、update_engineScheduleWaitMarkBootSuccessful()WaitForMergeOrSchedule() を呼び出します。これにより、マージの処理が開始されます。しかし、デバイスは古いスロットで再起動されます。マージがすでに開始しているため、デバイスは起動できず、動作不能になります。

ソースツリーに次の変更を追加します。CL 1664859 は省略可能です。

  • CL 1439792(CL 1439372 の前提条件)。
  • CL 1439372CleanupPreviousUpdateAction: 破棄の際の保留中のタスクのキャンセル)
  • CL 1663460markSlotSuccessful が遅れた場合の潜在的なワイルド ポインタのエラーの修正)
  • CL 1664859(省略可 - CleanupPreviousUpdateActionunittest を追加)

スキップしたメタデータによるデータの損失や破損を防ぐ

Android 11 以降では、ストレージ デバイスに非揮発性の書き戻しキャッシュがある場合、一定の条件下で、完了したマージのメタデータがスキップされて、データの喪失または損傷が生じることがあります。

条件:

  1. 1 つの例外セットのマージ操作を実行した後、merge_callback() が呼び出された。
  2. マージの完了を追跡する COW デバイスでメタデータが更新された。(この COW デバイスへのアップデートは適切にフラッシュされます。)

結果: ストレージ デバイスの最近のマージのキャッシュがフラッシュされていないため、システムがクラッシュする。

解決策を実行するには、以下をご覧ください。

dm-verity の設定が正しいことを確認する

Android 11 以降では、次の dm-verity オプションでデバイスが誤って設定されることがあります。

  • カーネルの CONFIG_DM_VERITY_AVB=y
  • AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO なしで任意の verity モード(AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE など)を使用するように設定されたブートローダー

このデバイス設定では、verity エラーがあると vbmeta パーティションが破損し、非 A/B デバイスが動作しなくなります。同様に、マージが開始されると、A/B デバイスも動作しなくなる可能性があります。AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO verity モードのみを使用します。

  1. カーネルで CONFIG_DM_VERITY_AVB=n を設定します
  2. 代わりに AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO モードを使用するようにデバイスを設定します

詳細については、実際のところ、verity のドキュメント「dm-verity エラーの処理」をご覧ください。

緊急システム シャットダウン時の I/O エラーに応じて verity 動作をスキップする

Android 11 以降では、サーマル シャットダウンの場合など、緊急システム シャットダウンが呼び出されると、ブロック デバイスは I/O リクエストを処理できなくなりますが、dm デバイスは動作します。この状態では、新しい dm I/O リクエストまたは処理中の I/O リクエストによって処理される I/O エラーが、誤判定である verity 破損状態につながるおそれがありあます。

システムのシャットダウン時、I/O エラーに応じて verity 動作をスキップするには、以下を使用します。

CL 1847875(シャットダウン中の I/O エラーに応じて verity 動作をスキップする)

DM_ANDROID_VERITY_AT_MOST_ONCE_DEFAULT_ENABLED がオフになっていることを確認する

4.19 以前のカーネルを実行している Android Go デバイスのカーネル構成には、DM_ANDROID_VERITY_AT_MOST_ONCE_DEFAULT_ENABLED=y が含まれている場合があります。この設定は仮想 A/B と互換性がありません。また、両方を一度に有効にするとまれにページが破損することがある、という問題が報告されています。

4.19 以前のカーネルでは、カーネル構成で CONFIG_DM_ANDROID_VERITY_AT_MOST_ONCE_DEFAULT_ENABLED=n を設定して無効にしてください。

5.4 以降のカーネルでは、このコードは削除されており、構成オプションは使用できません。

マージしたファイルが正しく構成されていることを確認する

システム イメージとベンダー イメージを別々にビルドし、merge_target_files を使用してマージする場合は、マージ処理中に仮想 A/B の構成が抜け落ちてしまう場合があります。マージされたターゲット ファイルの仮想 A/B の構成が正しいことを確認するには、CL 2084183(動的パーティション情報内の同一の Key-Value ペアをマージする)というパッチを適用します。

必要なコンポーネントを更新する

Android 13 では、snapuserd をベンダー RAM ディスクから汎用 RAM ディスクに移動しました。デバイスを Android 13 にアップグレードする場合、ベンダー RAM ディスクと汎用 RAM ディスクの両方に snapuserd のコピーが含まれる可能性があります。この場合、仮想 A/B には snapuserd のシステムコピーが必要になります。snapuserd の正しいコピーを確実に配置するには、CL 2031243snapuserd を first_stage_ramdisk にコピーする)を適用します。