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

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 カーネルの要件を含む)。また、Android 10 における 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 を使用すると、汎用システム イメージ(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/* の下に自動的に作成するため)。

RAM ディスク

Android 10 では、第 1 ステージの RAM ディスクには、第 1 ステージの init バイナリ(fstab エントリで指定された初期マウントを実行)と、ベンダーの fstab ファイルが含まれています(Android 9 と同様に、system.img には $TARGET_ROOT_OUT の内容が含まれています)。

  • 起動 RAM ディスク(非 A/B)を備えたデバイスの場合、第 1 ステージの init は、/init にある静的な実行可能ファイルです。これらのデバイスは、system.img/system としてマウントしてから、ルート切り替え操作を実行して /system のマウントを / に移動します。マウントが完了すると、RAM ディスクの内容は解放されます。
  • リカバリを RAM ディスクとして使用するデバイスの場合、第 1 ステージの init はリカバリ用の RAM ディスク内の /init にあります。これらのデバイスは、最初にルートを /first_stage_ramdisk に切り替えてリカバリ コンポーネントを環境から削除します。次に、起動 RAM ディスクを備えたデバイスと同じ手順を実行します(system.img/system としてマウントし、ルートを切り替えてそのマウントを / に移動し、マウント後に RAM ディスクの内容を解放します)。androidboot.force_normal_boot=1 がカーネル コマンドラインに存在する場合、デバイスはリカバリモードではなく、通常どおり(Android で)起動します。

第 1 ステージの init が終了すると、selinux_setup 引数を指定して /system/bin/init を実行し、SELinux をコンパイルしてシステムにロードします。最後に、init は second_stage 引数を指定して /system/bin/init をもう一度実行します。この時点で、init のメインフェーズにより、init.rc スクリプトを使用して起動プロセスが実行および続行されます。

パーティション レイアウト(非 A/B デバイス)

以降のセクションでは、Android 10 以前と以降の非 A/B デバイスの、パーティション レイアウトの違いについて説明します。

boot.img

RAM ディスク
(Android 8.x 以前)
System as root
(Android 9)
RAM ディスク
(Android 10)

カーネルと ramdisk.img が含まれます。


    ramdisk.img
      -/
        - init.rc
        - init
        - etc -> /system/etc
        - system/ (mount point)
        - vendor/ (mount point)
        - odm/ (mount point)
        ...
        
通常のブートカーネルのみが含まれます。

カーネルと ramdisk.img が含まれます。


    ramdisk.img
      -/
        - init
        - vendor fstab files
        - system/ (mount point)
        - vendor/ (mount point)
        - odm/ (mount point)
        ...
        

recovery.img

リカバリ カーネルとリカバリ ramdisk.img が含まれます。

system.img

RAM ディスク
(Android 8.x 以前)
System as root
(Android 9)
RAM ディスク
(Android 10)

system.img が含まれます。


    system.img
      -/
        - bin/
        - etc
        - vendor -> /vendor
        - ...
       

$TARGET_SYSTEM_OUT$TARGET_ROOT_OUT のマージされたコンテンツが含まれます。


    system.img
      -/
        - init.rc
        - init
        - etc -> /system/etc
        - system/
          - bin/
          - etc/
          - vendor -> /vendor
          - ...
        - vendor/ (mount point)
        - odm/ (mount point)
        ...
        

$TARGET_SYSTEM_OUT$TARGET_ROOT_OUT のマージされたコンテンツが含まれます。


    system.img
      -/
        - init.rc
        - init -> /system/bin/init
        - etc -> /system/etc
        - system/
          - bin/
          - etc/
          - vendor -> /vendor
          - ...
        - vendor/ (mount point)
        - odm/ (mount point)
        ...
        

パーティション レイアウト(A/B デバイス)

以降のセクションでは、Android 10 以前と以降の A/B デバイスの、パーティション レイアウトの違いについて説明します。

boot.img

System as root
(Android 9)
RAM ディスク
(Android 10)
通常のブートカーネルとリカバリ用 RAM ディスク(BOARD_USES_RECOVERY_AS_BOOT := true)が含まれます。

リカバリ用 RAM ディスクは、リカバリを起動する場合にのみ使用します。
通常のブートカーネルとリカバリ用 RAM ディスク(BOARD_USES_RECOVERY_AS_BOOT := true)が含まれます。

リカバリ用 RAM ディスクは、リカバリと Android の両方で起動します。

    ramdisk.img
      -/
        - init -> /system/bin/init
        - first_stage_ramdisk
           - vendor fstab files
        - etc -> /system/etc
        - system/ (mount point)
        - vendor/ (mount point)
        - odm/ (mount point)
        ...
        

system.img

$TARGET_SYSTEM_OUT$TARGET_ROOT_OUT のマージされたコンテンツが含まれます。

    system.img
      -/
        - init.rc
        - init -> /system/bin/init
        - etc -> /system/etc
        - system/
          - bin/
          - etc/
          - vendor -> /vendor
          - ...
        - vendor/ (mount point)
        - odm/ (mount point)
        ...