パーティション レイアウト

Android 10 では、ルート ファイル システムが ramdisk.img に含まれなくなった代わりに、system.img にマージされています(BOARD_BUILD_SYSTEM_ROOT_IMAGE が設定されているかのように、system.img が常に作成されます)。Android 10 を搭載したデバイスに必要な要件と操作を以下に記載します。

  • system-as-root パーティション レイアウトを使用します(ビルドにより自動的に適用され、この動作を変更するオプションは存在しません)。
  • RAM ディスクを使用する必要があります。これは dm-linear では必須です。
  • BOARD_BUILD_SYSTEM_ROOT_IMAGEfalse に設定する必要があります。この設定は、RAM ディスクを使用するデバイスと使用しないデバイス(つまり、代わりに system.img マウントを直接使用するデバイス)を区別する目的にのみ使用されます。

system-as-root 構成の意味は、Android 9 と Android 10 で異なります。Android 9 の system-as-root 構成では、BOARD_BUILD_SYSTEM_ROOT_IMAGEtrue に設定されています。これにより、ビルドはルート ファイル システムを system.img にマージし、system.img をルート ファイル システム(rootfs)としてマウントします。この構成は、Android 9 でリリースするデバイスでは必須ですが、Android 9 にアップグレードするデバイスと、以前のバージョンの Android を実行しているデバイスでは任意です。Android 10 の system-as-root 構成では、ビルドは常に $TARGET_SYSTEM_OUT$TARGET_ROOT_OUTsystem.img にマージします。この構成は、Android 10 を実行するすべてのデバイスのデフォルト動作です。

Android 10 では、動的パーティション(無線(OTA)アップデートによるパーティションの作成、サイズ変更、破棄を可能にするユーザー空間パーティショニング システム)をサポートするために、さらに変更が加えられています。この変更の一環として、Linux カーネルは Android 10 を実行するデバイスで論理システム パーティションをマウントできなくなったため、この操作は第 1 ステージの init で処理されます。

以降のセクションでは、システム専用の OTA の system-as-root の要件について説明し、system-as-root を使用するようにデバイスをアップデートするためのガイダンスを示します(パーティション レイアウトの変更、dm-verity カーネルの要件を含む)。RAM ディスクの変更の詳細については、RAM ディスク パーティションをご覧ください。

システム専用 OTA について

システム専用 OTA を使用すると、Android のリリースで他のパーティションを変更せずに system.imgproduct.img をアップデートできますが、それには system-as-root パーティション レイアウトが必要です。Android 10 を実行するすべてのデバイスで、system-as-root パーティション レイアウトを使用してシステム専用 OTA を有効にする必要があります。

  • A/B デバイスでは system パーティションを rootfs としてマウントしていますが、すでに system-as-root を使用しているため、システム OTA をサポートするための変更は必要ありません。
  • 非 A/B デバイスでは system パーティションを /system にマウントしていますが、システム OTA をサポートするには system-as-root パーティション レイアウトを使用するようにアップデートする必要があります。

A/B デバイスと非 A/B デバイスの詳細については、A/B(シームレス)システム アップデートをご覧ください。

ベンダー オーバーレイを使用する(<=AOSP 14)

ベンダー オーバーレイを使用すると、デバイスの起動時に vendor パーティションに変更をオーバーレイできます。ベンダー オーバーレイは、デバイスの起動時に vendor パーティションにオーバーレイされるベンダー モジュールのセットで、product パーティションにあり、既存のモジュールに置き換わって追加されます。

デバイスが起動すると、init プロセスは第 1 ステージのマウントを完了し、デフォルトのプロパティを読み取ります。次に、/product/vendor_overlay/<target_vendor_version> を検索し、以下の条件に一致する場合、対応する vendor パーティション ディレクトリに各サブディレクトリをマウントします。

  • /vendor/<overlay_dir> が存在する。
  • /product/vendor_overlay/<target_vendor_version>/<overlay_dir>/vendor/<overlay_dir> と同じファイル コンテキストがある。
  • init/vendor/<overlay_dir> のファイル コンテキストにマウントすることを許可されている。

ベンダー オーバーレイを実装する

ベンダー オーバーレイ ファイルを /product/vendor_overlay/<target_vendor_version> にインストールします。これらのファイルは、デバイスの起動時に vendor パーティションにオーバーレイし、同じ名前のファイルを置き換えて新しいファイルを追加します。ベンダー オーバーレイは、vendor パーティションからファイルを削除することはできません。

ベンダー オーバーレイ ファイルには、vendor パーティションで置き換えるターゲット ファイルと同じファイル コンテキストが存在する必要があります。デフォルトでは、/product/vendor_overlay/<target_vendor_version> ディレクトリのファイルには vendor_file コンテキストが存在します。ベンダー オーバーレイ ファイルと置き換えるファイルのファイル コンテキストに不一致がある場合は、デバイス固有の sepolicy でファイル コンテキストを指定します。ファイル コンテキストはディレクトリ レベルで設定されます。ベンダー オーバーレイ ディレクトリのファイル コンテキストがターゲット ディレクトリと一致せず、デバイス固有の sepolicy で適切なファイル コンテキストが指定されていない場合、そのベンダーのオーバーレイ ディレクトリはターゲット ディレクトリにオーバーレイされません。

ベンダー オーバーレイを使用するには、カーネルで CONFIG_OVERLAY_FS=y を設定して OverlayFS を有効にする必要があります。また、カーネルを共通のカーネル 4.4 以降からマージするか、"overlayfs: override_creds=off option bypass creator_cred" を使用してパッチを当てる必要があります。

ベンダー オーバーレイの実装例

次の手順は、/vendor/lib/*/vendor/etc/*/vendor/app/* の各ディレクトリをオーバーレイするベンダー オーバーレイの実装を示しています。

  1. 事前ビルド済みのベンダー ファイルを device/<vendor>/<target>/vendor_overlay/<target_vendor_version>/ に追加します。

    device/google/device/vendor_overlay/28/lib/libfoo.so
    device/google/device/vendor_overlay/28/lib/libbar.so
    device/google/device/vendor_overlay/28/etc/baz.xml
    device/google/device/vendor_overlay/28/app/qux.apk
  2. 事前ビルド済みのベンダー ファイルを device/google/device/device.mkproduct/vendor_overlay にインストールします。

    PRODUCT_COPY_FILES += \
        $(call find-copy-subdir-files,*,device/google/device/vendor_overlay,$(TARGET_COPY_OUT_PRODUCT)/vendor_overlay)
  3. ターゲットの vendor パーティション ファイルに vendor_file 以外のコンテキストが存在する場合、ファイル コンテキストを定義します。/vendor/lib/*vendor_file コンテキストを使用するため、この例にはそのディレクトリは含まれていません。

    device/google/device-sepolicy/private/file_contexts に次のように追加します。

    /(product|system/product)/vendor_overlay/[0-9]+/etc(/.*)?   u:object_r:vendor_configs_file:s0
    /(product|system/product)/vendor_overlay/[0-9]+/app(/.*)?   u:object_r:vendor_app_file:s0
  4. init プロセスが、ベンダー オーバーレイを vendor_file 以外のファイル コンテキストにマウントすることを許可します。init プロセスにはすでに vendor_file コンテキストにマウントする権限があるため、この例では vendor_file のポリシーを定義しません。

    device/google/device-sepolicy/public/init.te に次のように追加します。

    allow init vendor_configs_file:dir mounton;
    allow init vendor_app_file:dir mounton;

ベンダー オーバーレイを検証する

ベンダーのオーバーレイ構成を検証するには、/product/vendor_overlay/<target_vendor_version>/<overlay_dir> にファイルを追加し、ファイルが /vendor/<overlay_dir> のファイルにオーバーレイされているかどうかを確認します。

userdebug ビルドの場合、Atest のテスト モジュールがあります。

$ atest -v fs_mgr_vendor_overlay_test

system-as-root にアップデートする

system-as-root を使用するように非 A/B デバイスをアップデートするには、boot.imgsystem.img のパーティショニング スキームをアップデートして、dm-verity を設定し、デバイス固有のルートフォルダへのブート依存関係を削除します。

パーティションをアップデートする

/bootリカバリ パーティションとして再利用する A/B デバイスとは異なり、非 A/B デバイスにはフォールバック パーティションがないため、/recovery パーティションを分離しておく必要があります(たとえば boot_a から boot_b)。/recovery が非 A/B デバイスで削除され、A/B スキームと同様にされた場合、/boot パーティションのアップデートが失敗している間にリカバリモードが中断する可能性があります。そのため非 A/B デバイスでは、/recovery パーティションは必ず /boot から分離されたパーティションであることが必要です。これは、リカバリ イメージが引き続き遅れてアップデートされることを意味します(Android 8.1.0 以前を実行しているデバイスと同じ)。

次の表に、Android 9 よりも前と後の非 A/B デバイスのイメージ パーティションの違いを示します。

画像 RAM ディスク(9 より前) system-as-root(9 より後)
boot.img カーネルと ramdisk.img が含まれます。
ramdisk.img
  -/
    - init.rc
    - init
    - etc -> /system/etc
    - system/ (mount point)
    - vendor/ (mount point)
    - odm/ (mount point)
    ...
通常のブートカーネルのみが含まれます。
recovery.img リカバリ カーネルとリカバリ ramdisk.img が含まれます。
system.img 以下のものが含まれます。
system.img
  -/
    - bin/
    - etc
    - vendor -> /vendor
    - ...
元の system.imgramdisk.img のマージされたコンテンツが含まれます。
system.img
  -/
    - init.rc
    - init
    - etc -> /system/etc
    - system/
      - bin/
      - etc/
      - vendor -> /vendor
      - ...
    - vendor/ (mount point)
    - odm/ (mount point)
    ...

パーティション自体は変更されません。RAM ディスクと system-as-root は次のパーティション スキームを使用します。

  • /boot
  • /system
  • /system
  • /recovery
  • /vendor など

dm-verity を設定する

system-as-root では、カーネルは dm-verity を使用して、/(マウント ポイント)の下に system.img をマウントする必要があります。AOSP は、system.img 用に次の dm-verity 実装をサポートしています。

vboot 1.0

vboot 1.0 の場合、カーネルは /system 上の Android 固有のメタデータを解析し、dm-verity パラメータに変換して、dm-verity を設定する必要があります(これらのカーネルパッチが必要)。次の例は、カーネル コマンドラインの system-as-root 用の、dm-verity 関連の設定を示しています。

ro root=/dev/dm-0 rootwait skip_initramfs init=/init
dm="system none ro,0 1 android-verity /dev/sda34"
veritykeyid=id:7e4333f9bba00adfe0ede979e28ed1920492b40f

vboot 2.0

vboot 2.0(AVB)の場合、ブートローダーは external/avb/libavb を統合し、/systemハッシュツリー記述子を解析して、dm-verity パラメータに変換し、最後にカーネル コマンドラインを介してパラメータをカーネルに渡す必要があります(/system のハッシュツリー記述子は、/vbmeta または /system それ自体に存在する可能性があります)。

vboot 2.0 には、次のカーネルパッチが必要です。

次の例は、カーネル コマンドラインの system-as-root 用の、dm-verity 関連の設定を示しています。

ro root=/dev/dm-0 rootwait  skip_initramfs init=/init

dm="1 vroot none ro 1,0 5159992 verity 1
PARTUUID=00000016-0000-0000-0000-000000000000
PARTUUID=00000016-0000-0000-0000-000000000000 4096 4096 644999 644999
sha1 d80b4a8be3b58a8ab86fad1b498640892d4843a2
8d08feed2f55c418fb63447fec0d32b1b107e42c 10 restart_on_corruption
ignore_zero_blocks use_fec_from_device
PARTUUID=00000016-0000-0000-0000-000000000000 fec_roots 2 fec_blocks
650080 fec_start 650080"

デバイス固有のルートフォルダを使用する

system-as-root を使用すると、Generic System Image(GSI)がデバイス上でフラッシュされた後(ベンダー テストスイート テストを実行する前)、ルート ディレクトリのコンテンツ全体が system-as-root GSI に置き換えられるため、BOARD_ROOT_EXTRA_FOLDERS を使用して追加されたデバイス固有のルートフォルダはすべて削除されます。デバイス固有のルートフォルダへの依存関係が存在する場合(マウント ポイントとして使用されている場合など)、これらのフォルダが削除されることでデバイスが起動できなくなる可能性があります。

この問題を回避するには、デバイス固有のルートフォルダを追加する際に BOARD_ROOT_EXTRA_FOLDERS を使用しないようにします。デバイス固有のマウント ポイントを指定する必要がある場合は、/mnt/vendor/<mount point> を使用します(これらの変更リストに追加されています)。これらのベンダー固有のマウント ポイントは、fstab デバイスツリー(第 1 ステージのマウントの場合)と /vendor/etc/fstab.{ro.hardware} ファイルで追加設定なしで直接指定できます(fs_mgr/mnt/vendor/* の下に自動的に作成するため)。