このページでは、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 の周囲のパーティションと、インターフェース上のパーティションおよびポリシー全体を対象とするバージョニングされたインターフェースを示しています。このセクションでは、それぞれのパーティションとインターフェースについて詳しく説明します。
図 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 ライブラリ
- HIDL(パススルー HAL は
製品インターフェース: 製品インターフェースは、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:
true
を Android.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 用の推奨手順
図 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
ファイル自体を変更することは許可されていません。
図 3. OEM システム イメージで generic_system.mk を継承する
ステップ 2. OEM GSI に AOSP GSI と同じファイルリストを設定する
この段階で、OEM GSI に追加ファイルを設定することはできません。OEM 固有のファイルは、system_ext
パーティションまたは product
パーティションに移動する必要があります。
図 4. 追加ファイルを OEM GSI から移動する
ステップ 3: OEM GSI で変更されたファイルを制限する許可リストを定義する
変更されたファイルをチェックするため、OEM は compare_images
ツールを使用して、AOSP GSI と OEM GSI を比較できます。AOSP lunch ターゲット generic_system_*
から AOSP GSI を取得します。
allowlist
パラメータを指定して compare_images
ツールを定期的に実行することにより、許可リストに含まれていない変更をモニタリングできます。これにより、OEM GSI に追加の変更を加える必要がなくなります。
図 5. 許可リストを定義して OEM GSI で変更されたファイルのリストを削減する
ステップ 4. OEM GSI のバイナリを AOSP GSI のバイナリと同じにする
許可リストをクリーンアップすると、OEM は自身の製品でシステム イメージとして AOSP GSI を使用できます。OEM が許可リストをクリーンアップするには、OEM GSI の変更を放棄するか、そうした変更を AOSP にアップストリームして 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_LEVEL
が 30
以上である場合、自動的に設定されます。詳しくは、製品パーティション インターフェースを適用するをご覧ください。
/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
ファイルを更新するよう依頼してください。