Android 共有システム イメージ

このページでは、Android デバイスの OEM が製品ライン全体で独自の共有システム イメージ(SSI)を提供するために使用できるメカニズムをいくつか紹介します。また、AOSP でビルドされた Generic System Image(GSI)に基づいて OEM が所有する SSI をビルドする手順を示します。

背景

プロジェクト Treble で、モノリシック Android は、ハードウェア固有の領域(ベンダー実装)と汎用 OS の領域(Android OS フレームワーク)の 2 つに分割されました。それぞれの領域のソフトウェアは独立したパーティションにインストールされます。つまり、ハードウェア固有のソフトウェアはベンダー パーティション、汎用 OS ソフトウェアはシステム パーティションに配置されます。ベンダー インターフェース(VINTF)と呼ばれるバージョニングされたインターフェースは、2 つのパーティションに対して定義され、適用されます。このパーティショニング システムを使用すると、ベンダー パーティションを変更せずにシステム パーティションを変更できます。また、その逆も可能です。

このドキュメントの目的

これまで AOSP でリリースされたフレームワーク コードは、Treble アーキテクチャに対応しており、古いベンダー実装との下位互換性を維持しています。たとえば、Android 10 の AOSP ソースからビルドされた Generic System Image は、Android 8 以上を搭載したすべての Treble 対応デバイスで動作します。消費者デバイスに搭載されている Android のバージョンは、SoC ベンダーと OEM によって変更されます(Android リリースのライフサイクルをご覧ください)。フレームワークに加えられるこのような変更と拡張は、下位互換性の維持を意図して記述されていなかったため、OS のアップグレードに複雑さとコストの増大をもたらしていました。デバイスごとに固有の変更や修正があることも、Android OS バージョンのアップグレードのコストと複雑さを増大させていました。

Android 11 より前は、パートナーが Android OS フレームワークに対してモジュール型の拡張機能を構築できる明確なアーキテクチャは存在しませんでした。このドキュメントでは、SoC ベンダーと OEM が SSI を作成するために実施できる手順について説明します。この手順では、Android OS フレームワーク ソースからビルドされた 1 つのイメージを複数のデバイスで再利用します。これで、ベンダー実装との下位互換性が維持されるようになり、Android OS のアップグレードにおける複雑さとコストを大幅に削減できます。SSI の作成に必要な特定の手順については、GSI ベースの SSI 用の推奨手順セクションをご覧ください。なお、4 つの手順をすべて使用する必要はありません。どの手順を選択するかは実装によって決まります。たとえば、手順 1 のみを選択します。

SSI の概要

SSI では、製品固有のソフトウェア コンポーネントと OEM 拡張機能が新しい /product パーティションに配置されます。/product パーティション内のコンポーネントは、明確に定義された、安定したインターフェースを使用して、/system パーティション内のコンポーネントとやり取りします。OEM は、1 つの SSI をビルドするか、それとも複数のデバイス SKU で使用する少数の SSI をビルドするかを選択できます。Android OS の新しいバージョンがリリースされるとき、OEM は SSI を最新の Android リリースにアップデートするために一度だけ投資します。OEM は、/product パーティションを更新しなくても、この SSI を再利用して複数のデバイスをアップデートできます。

OEM と SoC ベンダーは、OEM が必要とするすべてのカスタム機能と変更を含む SSI をビルドします。このページで紹介するメカニズムとおすすめの方法は、OEM が以下の主要な目標を達成するために使用することを目的としています。

  • 複数のデバイス SKU で SSI を再利用する。
  • OS のアップグレードをより簡単にするため、モジュール型の拡張機能を使用して Android システムをアップデートする。

製品固有のコンポーネントを製品パーティションに分離するという中核的なコンセプトは、SoC 固有のコンポーネントをベンダー パーティションに分離するという Treble のコンセプトと似ています。製品インターフェース(VINTF と似ています)では、SSI と製品パーティション間の通信が可能です。SSI に関しては、「コンポーネント」という用語は、イメージにインストールされているすべてのリソース、バイナリ、テキスト、ライブラリなどを意味しており、実質的にパーティションを指します。

SSI の周囲のパーティション

図 1 は、SSI の周囲のパーティションと、インターフェース上のパーティションおよびポリシー全体を対象とするバージョニングされたインターフェースを示しています。このセクションでは、それぞれのパーティションとインターフェースについて詳しく説明します。

SSI の周囲のパーティションとインターフェースを示すブロック図

図 1. SSI の周囲のパーティションとインターフェース

イメージとパーティション

このセクションの説明では、「イメージ」という用語と「パーティション」という用語を区別します。

  • イメージとは、独立して更新できるソフトウェア コンポーネントを意味する概念です。
  • パーティションとは、独立して更新できる物理ストレージ領域です。

図 1 の各領域は、次のように定義されます。

  • SSI: SSI は、OEM 共通のイメージで、複数のデバイスに存在する可能性があります。ハードウェア固有または製品固有のコンポーネントは含んでいません。特定の SSI に含まれるすべてのものは、定義上、その SSI を使用するすべてのデバイス間で共有されます。SSI は、図 1 に示されているように、単一の /system イメージ、または /system および /system_ext パーティションで構成されます。

    • /system パーティションには、AOSP ベースのコンポーネントが含まれています。一方、/system_ext(実装されている場合)には、AOSP コンポーネントと密結合された OEM と SoC ベンダーの拡張機能およびコンポーネントが含まれています。たとえば、OEM 独自のアプリにカスタム API を提供する OEM Java フレームワーク ライブラリは、/system パーティションよりも /system_ext に配置する方が適切です。/system パーティションと /system_ext パーティションの両方のコンテンツは、OEM が変更した Android ソースからビルドされます。

    • /system_ext パーティションは必須ではありませんが、AOSP ベースのコンポーネントと密結合されているカスタム機能と拡張機能に使用すると便利です。この区別は、そうしたコンポーネントを /system_ext パーティションから /product パーティションに一定期間移動する際に、必要な変更を確認するために役立ちます。

  • 製品: Android OS に対する OEM のカスタマイズと拡張機能を表す、製品固有またはデバイス固有のコンポーネントのコレクション。SoC 固有のコンポーネントは /vendor パーティションに配置します。SoC ベンダーは、適切なコンポーネント(SoC に依存しないコンポーネントなど)のために /product パーティションを使用することもできます。たとえば、SoC ベンダーが SoC に依存しないコンポーネントを OEM カスタマーに提供している場合(製品に同梱するかどうかは任意)、SoC ベンダーはそのコンポーネントを製品イメージに配置できます。コンポーネントの場所は、その所有者が誰かではなく、その目的によって決まります。

  • ベンダー: SoC 固有のコンポーネントのコレクション。

  • ODM: SoC によって提供されないボード固有のコンポーネントのコレクション。一般的に、SoC ベンダーはベンダー イメージを所有し、デバイス メーカーは ODM イメージを所有します。独立した /odm パーティションが存在しない場合は、SoC ベンダー イメージと ODM イメージの両方が /vendor パーティションに混在します。

イメージ間のインターフェース

SSI の周囲には、ベンダー イメージと製品イメージ用に 2 つの主要なインターフェースがあります。

  • ベンダー インターフェース(VINTF): VINTF は、ベンダー イメージおよび ODM イメージ内に存在するコンポーネントに対するインターフェースです。製品イメージとシステム イメージに含まれるコンポーネントは、このインターフェースを介してのみ、ベンダー イメージおよび ODM イメージとやり取りできます。たとえば、ベンダー イメージは、システム イメージの非公開の領域に依存することはできません。その逆も同様です。これは元々、イメージをシステム パーティションとベンダー パーティションに分割した、プロジェクト Treble で定義されたものです。インターフェースは、次のメカニズムを使用して記述されています。

    • HIDL(パススルー HAL は system モジュールと system_ext モジュールでのみ使用可能)
    • 安定版の AIDL
    • 構成
      • システム プロパティ API
      • 構成ファイル スキーマ API
    • VNDK
    • Android SDK API
    • Java SDK ライブラリ
  • 製品インターフェース: 製品インターフェースは、SSI と製品イメージ間のインターフェースです。安定版インターフェースの定義では、SSI 内のシステム コンポーネントから製品コンポーネントが分離されています。製品インターフェースは、VINTF と同じ安定版インターフェースを必要とします。ただし、Android 11 以上でリリースされるデバイスには、VNDK API と Android SDK API のみが適用されます。

Android 11 の SSI を有効にする

このセクションでは、Android 11 で SSI をサポートする新機能の使用方法について説明します。

/system_ext パーティション

/system_ext パーティションは、Android 11 でオプションのパーティションとして導入されました(これは、/system パーティション内の AOSP 定義コンポーネントと密結合されている非 AOSP コンポーネント用の領域です)。/system_ext パーティションは、/system パーティションに対する OEM 固有の拡張機能と見なされます。ただし、この 2 つのパーティションにまたがるインターフェースは定義されていません。/system_ext パーティション内のコンポーネントは、/system パーティションに対して非公開 API 呼び出しを行うことができます。また、/system パーティション内のコンポーネントは、/system_ext パーティションに対して非公開 API 呼び出しを行うことができます。

2 つのパーティションは密結合されているため、Android の新しいバージョンがリリースされると、両方のパーティションが一緒にアップグレードされます。Android の以前のリリース用に作成された /system_ext パーティションは、次回の Android リリースの /system パーティションと互換性を持つ必要はありません。

/system_ext パーティションにモジュールをインストールするには、system_ext_specific: trueAndroid.bp ファイルに追加します。/system_ext パーティションがないデバイスの場合は、そのようなモジュールを /system パーティション内の ./system_ext サブディレクトリにインストールします。

歴史

ここでは、/system_ext パーティションに関する歴史を紹介します。このパーティションの設計目標は、すべての OEM 固有のコンポーネントを(共通のコンポーネントかどうかに関係なく)/product パーティションに配置することでした。しかし、一部のコンポーネントが /system パーティションと密結合されている場合は特に、すべてのコンポーネントを一度に移動することは事実上不可能でした。密結合されたコンポーネントを /product パーティションに移動するには、製品インターフェースを拡張する必要があります。そのためには、しばしばコンポーネント自体を徹底的にリファクタリングする必要がありました。これには多くの時間と労力がかかります。/system_ext パーティションは、/product パーティションに移動する準備ができていないコンポーネントを一時的にホストする場所として導入されました。SSI の目標は、最終的に /system_ext パーティションをなくすことでした。

しかし、/system_ext パーティションは、/system パーティションを AOSP のできるだけ近くに置いておくために便利です。SSI では、アップグレード処理のほとんどは /system パーティションおよび /system_ext パーティション内のコンポーネントに対するものです。AOSP のソースと可能な限り類似したソースからシステム イメージがビルドされている場合は、アップグレード処理を system_ext イメージに集中させることができます。

/system パーティションと /system_ext パーティションからコンポーネントを切り離して /product パーティションに移動する

Android 9 では、/system パーティションと結合された /product パーティション が導入されました。/product パーティション内のモジュールは、制限なしでシステム リソースを使用します。その逆も同様です。Android 10 では SSI を使用可能にするために、製品コンポーネントが /system_ext パーティションと /product パーティションに分割されました。/system_ext パーティションは、システム コンポーネントの使用について、Android 9 で /product パーティションが従っていた制限に従う必要はありません。Android 10 以降、/product パーティションは、/system パーティションから切り離される必要があります。また、/system パーティションと /system_ext パーティションからの安定版インターフェースを使用する必要があります。

/system_ext partition セクションで説明しているように、/system_ext パーティションの主な目的はバンドルされた製品モジュールをインストールすることではなく、システム機能を拡張することです。そのためには、製品固有のモジュールを切り離して /product パーティションに移動します。製品固有のモジュールを切り離すと、/system_ext がデバイス共通になります(詳しくは、/system_ext パーティションを共通にするをご覧ください)。

/product パーティションをシステム コンポーネントから切り離すには、プロジェクト Treble ですでに切り離されていた /vendor パーティションと同じ適用ポリシーが /product パーティションに存在する必要があります。

Android 11 以降、/product パーティション用のネイティブ インターフェースと Java インターフェースは、下記のように適用されます。詳しくは、製品パーティション インターフェースを適用するをご覧ください。

  • ネイティブ インターフェース: /product パーティション内のネイティブ モジュールは、他のパーティションから切り離される必要があります。製品モジュールからの依存関係は、/system パーティションからの一部の VNDK ライブラリ(LLNDK を含む)のみが許可されます。製品アプリが依存する JNI ライブラリは、NDK ライブラリであることが必要です。
  • Java インターフェース: /product パーティション内の Java(アプリ)モジュールは、隠し API を使用できません。それらは不安定だからです。こうしたモジュールは、/system パーティションからの公開 API とシステム API、および /system パーティションまたは /system_ext パーティション内の Java SDK ライブラリのみを使用する必要があります。カスタム API については、Java SDK ライブラリを定義できます。

GSI ベースの SSI 用の推奨手順

GSI ベースの SSI 用の推奨パーティション

図 2. GSI ベースの SSI 用の推奨パーティション

Generic System Image(GSI)は、AOSP から直接ビルドされたシステム イメージです。これは、Treble コンプライアンス テスト(CTS-on-GSI など)に使用されます。また、Android の必要なバージョンを搭載した実際のデバイスがない場合にアプリ デベロッパーがアプリの互換性をテストするための参照プラットフォームとしても使用されます。

OEM は、GSI を使用して独自の SSI を作成することもできます。イメージとパーティションで説明しているように、SSI は、AOSP 定義コンポーネント用のシステム イメージと OEM 定義コンポーネント用の system_ext イメージで構成されます。GSI を system イメージとして使用すると、OEM はアップグレードを system_ext イメージに集中させることができます。

このセクションでは、AOSP システム イメージまたは AOSP によく似たシステム イメージを使用しつつ、/system_ext および /product パーティションに対するカスタマイズをモジュール化する OEM 向けのガイドを提供します。OEM が AOSP ソースからシステム イメージをビルドする場合、ビルドするシステム イメージを、AOSP が提供する GSI に置き換えることができます。ただし、OEM は(GSI をそのまま使用して)最終ステップまで一気に進む必要はありません。

ステップ 1. OEM のシステム イメージ(OEM GSI)で generic_system.mk を継承する

generic_system.mk(Android 11 では mainline_system.mk という名前でしたが、AOSP で名前が generic_system.mk に変更されました)を継承すると、AOSP GSI に存在するすべてのファイルがシステム イメージ(OEM GSI)に挿入されます。OEM は、OEM GSI が AOSP GSI ファイルに加えて OEM 固有のファイルを含むことができるように、これらのファイルを変更できます。ただし、OEM が generic_system.mk ファイル自体を変更することは許可されていません。

OEM システム イメージで generic_system.mk を継承する

図 3. OEM システム イメージで generic_system.mk を継承する

ステップ 2. OEM GSI に AOSP GSI と同じファイルリストを設定する

この段階で、OEM GSI に追加ファイルを設定することはできません。OEM 固有のファイルは、system_ext パーティションまたは product パーティションに移動する必要があります。

追加ファイルを OEM GSI から移動する

図 4. 追加ファイルを OEM GSI から移動する

ステップ 3: OEM GSI で変更されたファイルを制限する許可リストを定義する

変更されたファイルをチェックするため、OEM は compare_images ツールを使用して、AOSP GSI と OEM GSI を比較できます。AOSP lunch ターゲット generic_system_* から AOSP GSI を取得します。

allowlist パラメータを指定して compare_images ツールを定期的に実行することにより、許可リストに含まれていない変更をモニタリングできます。これにより、OEM GSI に追加の変更を加える必要がなくなります。

許可リストを定義して OEM GSI で変更されたファイルのリストを削減する

図 5. 許可リストを定義して OEM GSI で変更されたファイルのリストを削減する

ステップ 4. OEM GSI のバイナリを AOSP GSI のバイナリと同じにする

許可リストをクリーンアップすると、OEM は自身の製品でシステム イメージとして AOSP GSI を使用できます。OEM が許可リストをクリーンアップするには、OEM GSI の変更を放棄するか、そうした変更を AOSP にアップストリームして AOSP GSI に含まれるようにします。

OEM GSI のバイナリを AOSP GSI のバイナリと同じにする

図 6. OEM GSI のバイナリを AOSP GSI のバイナリと同じにする

OEM の SSI を定義する

ビルド時に /system パーティションを保護する

/system パーティションの製品固有の変更を避けて OEM GSI を定義するために、OEM は require-artifacts-in-path という makefile マクロを使用して、マクロが呼び出された後でシステム モジュールが宣言されることを防止できます。makefile の作成とアーティファクト パスチェックの有効化の例をご覧ください。

OEM は、製品固有のモジュールを一時的に /system パーティションにインストールすることを許可するためのリストを定義できます。ただし、OEM GSI を OEM のすべての製品で共通にするには、リストを空白にする必要があります。このプロセスは OEM GSI を定義するためのものであるため、AOSP GSI 用の手順から分離できます。

製品インターフェースを適用する

/product パーティションが切り離されていることを保証するため、OEM は、ネイティブ モジュールでは PRODUCT_PRODUCT_VNDK_VERSION:= current を設定し、Java モジュールでは PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE:= true を設定して、デバイスで確実に製品インターフェースが適用されるようにすることができます。これらの変数は、デバイスの PRODUCT_SHIPPING_API_LEVEL30 以上である場合、自動的に設定されます。詳しくは、製品パーティション インターフェースを適用するをご覧ください。

/system_ext パーティションを共通にする

/system_ext パーティションは、システムにバンドルされたデバイス固有のモジュールを持つことができるので、デバイスによって異なる場合があります。SSI は /system パーティションと /system_ext パーティションで構成されているため、/system_ext パーティションの違いは OEM が SSI を定義する際に妨げになります。OEM は、独自の SSI を作成し、違いを取り除いて /system_ext パーティションを共通にすることにより、複数のデバイスで SSI を共有できます。

このセクションでは、/system_ext パーティションを共通にするための推奨事項を示します。

システム パーティション内の隠し API を公開する

製品固有のアプリの多くは、製品パーティションで禁止されている隠し API を使用しているため、製品パーティションにインストールすることができません。デバイス固有のアプリを製品パーティションに移動するには、隠し API を取り除きます。

隠し API をアプリから取り除くには、代わりになる公開 API またはシステム API を見つけて置き換える方法をおすすめします。隠し API の代わりになる API がない場合、OEM は OEM 固有のデバイス用に新しいシステム API を定義して、AOSP に寄与することができます。

または、/system_ext パーティションに独自の Java SDK ライブラリを作成して、カスタム API を定義する方法もあります。システム パーティション内の隠し API を使用し、製品パーティションまたはベンダー パーティション内のアプリに API を提供できます。OEM は、下位互換性を維持するため、製品指向の API を凍結する必要があります。

すべての APK のスーパーセットを格納し、各デバイスの一部のパッケージのインストールをスキップする

システムにバンドルされている一部のパッケージは、デバイス間で共通ではありません。そのような APK モジュールを切り離して製品パーティションまたはベンダー パーティションに移動することが難しい場合があります。暫定的な解決策として、OEM は SSI にすべてのモジュールを格納してから、SKU プロパティ(ro.boot.hardware.sku)を使用して不要なモジュールをフィルタで除外できます。フィルタを使用するには、フレームワーク リソース config_disableApkUnlessMatchedSku_skus_list および config_disableApksUnlessMatchedSku_apk_list をオーバーレイします。

より正確に設定するには、不要なパッケージを無効にするブロードキャスト レシーバを宣言します。ブロードキャスト レシーバは setApplicationEnabledSetting を呼び出して、ACTION_BOOT_COMPLETED メッセージを受信したときにパッケージを無効にします。

静的リソース オーバーレイを使用する代わりに RRO を定義する

静的リソース オーバーレイは、オーバーレイされたパッケージを操作します。ただし、これは SSI の定義の妨げになる可能性があるため、RRO のプロパティがオンになっており、適切に設定されていることを確認してください。プロパティを次のように設定することにより、OEM はすべての自動生成されたオーバーレイを RRO として利用できます。

PRODUCT_ENFORCE_RRO_TARGETS := *
PRODUCT_ENFORCE_RRO_EXCLUDED_OVERLAYS := # leave it empty

詳細な構成が必要な場合は、自動生成された RRO に頼らず、手動で RRO を定義します。詳しくは、ランタイム リソース オーバーレイ(RRO)をご覧ください。OEM は、android:requiredSystemPropertyName 属性と android:requiredSystemPropertyValue 属性を使用して、システム プロパティに依存する条件付き RRO を定義することもできます。

よくある質問(FAQ)

複数の SSI を定義できますか?

定義できるかどうかは、デバイス(またはデバイス グループ)の共通性と特性によります。system_ext パーティションを共通にするで説明しているように、OEM は system_ext パーティションを共通にする方法を試みることができます。デバイス グループ間に多くの違いがある場合は、複数の SSI を定義することをおすすめします。

OEM GSI の generic_system.mk(mainline_system.mk)を変更できますか?

いいえ。ただし、OEM は generic_system.mk ファイルを継承する新しい makefile を OEM GSI 用に定義して、新しい makefile を使用できます。例については、製品パーティション インターフェースを適用するをご覧ください。

独自の実装と競合するモジュールを generic_system.mk から削除できますか?

いいえ。GSI には、起動可能かつテスト可能なモジュールの最小限のセットが含まれています。必要でないモジュールが含まれていると思われる場合は、バグとして報告し、AOSP で generic_system.mk ファイルを更新するよう依頼してください。