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

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(シームレス)システム アップデートをご覧ください。

ベンダー オーバーレイの使用

ベンダー オーバーレイを使用すると、デバイスの起動時に 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/* の下に自動的に作成するため)。