Android 8.1 以降では、ビルドシステムに VNDK サポートが組み込まれています。VNDK サポートが有効になると、ビルドシステムはモジュール間の依存関係をチェックし、ベンダー モジュールのベンダー固有のバリアントをビルドして、指定されたディレクトリにこれらのモジュールを自動的にインストールします。
VNDK ビルドのサポートの例
この例では、Android.bp
モジュール定義が、libexample
と名付けられたライブラリを定義します。vendor_available
プロパティは、フレームワーク モジュールとベンダー モジュールが libexample
に依存する可能性があることを示します。
図 1. サポートが有効になっている
フレームワークの実行可能ファイル /system/bin/foo
とベンダーの実行可能ファイル /vendor/bin/bar
は libexample
に依存し、shared_libs
プロパティに libexample
が指定されます。
libexample
がフレームワーク モジュールとベンダー モジュールの両方で使用される場合、libexample
の 2 つのバリアントがビルドされます。libexample
にちなんで名付けられるコアバリアントは、フレームワーク モジュールで使用され、libexample.vendor
にちなんで名付けられるベンダー バリアントは、ベンダー モジュールで使用されます。この 2 つのバリアントは、次のとおり、それぞれ異なるディレクトリにインストールされます。
- コアバリアントは
/system/lib[64]/libexample.so
にインストールされます。 - ベンダー バリアントは、
vndk.enabled
がtrue
であるため、VNDK APEX にインストールされます。
詳細については、モジュールの定義をご覧ください。
ビルドサポートを構成する
ビルドシステムの完全サポートをプロダクトのデバイスで有効にするには、BOARD_VNDK_VERSION
を BoardConfig.mk
に追加します。
BOARD_VNDK_VERSION := current
この設定は、グローバルに適用されます。BoardConfig.mk
で定義されると、すべてのモジュールがチェックされます。不適切なモジュールを拒否リストまたは許可リストに登録するメカニズムがないため、BOARD_VNDK_VERSION
を追加する前に不要な依存関係をすべて削除する必要があります。モジュールをテストしてコンパイルするには、次のように環境変数で BOARD_VNDK_VERSION
を設定します。
$ BOARD_VNDK_VERSION=current m module_name.vendor
BOARD_VNDK_VERSION
を有効にすると、いくつかのデフォルトのグローバル ヘッダー検索パスが削除されます。下記はその一部です。
frameworks/av/include
frameworks/native/include
frameworks/native/opengl/include
hardware/libhardware/include
hardware/libhardware_legacy/include
hardware/ril/include
libnativehelper/include
libnativehelper/include_deprecated
system/core/include
system/media/audio/include
モジュールがこれらのディレクトリのヘッダーに依存している場合は、header_libs
、static_libs
、または shared_libs
で依存関係を(明示的に)指定する必要があります。
VNDK APEX
Android 10 以前の場合、vndk.enabled
のモジュールは /system/lib[64]/vndk[-sp]-${VER}
にインストールされていました。Android 11 以降の場合、VNDK ライブラリは APEX 形式でパッケージ化されており、VNDK APEX の名前は com.android.vndk.v${VER}
です。デバイス設定に応じて、VNDK APEX はフラット化またはアンフラット化されており、正規パス /apex/com.android.vndk.v${VER}
から使用できます。
図 2. VNDK APEX。
モジュールの定義
BOARD_VNDK_VERSION
を使って Android をビルドするには、Android.mk
または Android.bp
のモジュール定義を変更する必要があります。このセクションでは、さまざまな種類のモジュールの定義、いくつかの VNDK 関連モジュールのプロパティ、ビルドシステムで実装される依存性チェックについて説明します。
ベンダー モジュール
ベンダー モジュールは、ベンダー固有の実行可能ファイル、またはベンダーのパーティションにインストールする必要のある共有ライブラリです。Android.bp
ファイルでは、ベンダー モジュールは、vendor プロパティまたは proprietary プロパティを true
に設定する必要があります。Android.mk
ファイルでは、ベンダー モジュールは、LOCAL_VENDOR_MODULE
または LOCAL_PROPRIETARY_MODULE
を true
に設定する必要があります。
BOARD_VNDK_VERSION
が定義されている場合、ビルドシステムはベンダー モジュールとフレームワーク モジュール間の依存関係を許可せず、次のような場合にエラーを発します。
vendor:true
のないモジュールが、vendor:true
のあるモジュールに依存している。または、vendor:true
のあるモジュールが、vendor:true
とvendor_available:true
のどちらもないllndk_library
以外のモジュールに依存している。
依存関係のチェックは、Android.bp
内の header_libs
、static_libs
、shared_libs
と、Android.mk
内の LOCAL_HEADER_LIBRARIES
、LOCAL_STATIC_LIBRARIES
、LOCAL_SHARED_LIBRARIES
に適用されます。
LL-NDK
LL-NDK 共有ライブラリは、安定した ABI を持つ共有ライブラリです。フレームワーク モジュールとベンダー モジュールは両方とも同じ最新の実装を共有します。LL-NDK 共有ライブラリごとに、cc_library
にシンボル ファイルを指定して llndk
プロパティを含めます。
cc_library { name: "libvndksupport", llndk: { symbol_file: "libvndksupport.map.txt", }, }
シンボル ファイルには、ベンダー モジュールで表示されるシンボルを記載します。次に例を示します。
LIBVNDKSUPPORT { global: android_load_sphal_library; # llndk android_unload_sphal_library; # llndk local: *; };
ビルドシステムは、シンボル ファイルに基づいて、ベンダー モジュール用のスタブ共有ライブラリを生成します。BOARD_VNDK_VERSION
が有効になると、ベンダー モジュールはこれらのライブラリとリンクします。次のような場合のみ、シンボルがスタブ共有ライブラリに含まれます。
- セクションの末尾に
_PRIVATE
または_PLATFORM
が定義されていない、かつ #platform-only
タグがない、かつ#introduce*
タグがないかタグがターゲットと一致している
VNDK
Android.bp
ファイルでは、cc_library
、cc_library_static
、cc_library_shared
、cc_library_headers
の各モジュール定義が、vendor_available
、vndk.enabled
、vndk.support_system_process
の 3 つの VNDK 関連プロパティをサポートします。
vendor_available
または vndk.enabled
が true
の場合、2 つのバリアント(コアとベンダー)をビルドされることがあります。コアバリアントはフレームワーク モジュールとして、ベンダー バリアントはベンダー モジュールとして処理します。一部のフレームワーク モジュールがこのモジュールに依存している場合、コアバリアントがビルドされます。一部のベンダー モジュールがこのモジュールに依存している場合、ベンダー バリアントがビルドされます。ビルドシステムは、以下の依存関係をチェックします。
- コアバリアントは常にフレームワークのみであり、ベンダー モジュールからはアクセスできない。
- ベンダー バリアントは、フレームワーク モジュールからは常にアクセスできない。
header_libs
、static_libs
、またはshared_libs
に指定されるベンダー バリアントのすべての依存関係は、llndk_library
であるか、vendor_available
またはvndk.enabled
の指定されたモジュールであること。vendor_available
がtrue
の場合、ベンダー バリアントはすべてのベンダー モジュールからアクセスできる。vendor_available
がfalse
の場合、ベンダー バリアントは他の VNDK または VNDK-SP モジュールからのみアクセスできる(つまり、vendor:true
のモジュールはvendor_available:false
のモジュールにリンクできまない)。
cc_library
または cc_library_shared
のデフォルトのインストール パスは、以下のルールによって決まります。
- コアバリアントは
/system/lib[64]
にインストールされる。 - ベンダー バリアントのインストール パスは状況によって異なる。
vndk.enabled
がfalse
の場合、ベンダー バリアントは/vendor/lib[64]
にインストールされる。vndk.enabled
がtrue
の場合、ベンダー バリアントは VNDK APEX(com.android.vndk.v${VER}
)にインストールされる。
下記の表に、ビルドシステムがベンダー バリアントをどのように処理するかをまとめます。
vendor_available | vndk の有効化 |
vndk support_same_process |
ベンダー バリアントの説明 |
---|---|---|---|
true |
false |
false |
ベンダー バリアントは VND-ONLY です。共有ライブラリは /vendor/lib[64] にインストールされます。 |
true |
無効(ビルドエラー) | ||
true |
false |
ベンダー バリアントは VNDK です。共有ライブラリは VNDK APEX にインストールされます。 | |
true |
ベンダー バリアントは VNDK-SP です。共有ライブラリは VNDK APEX にインストールされます。 | ||
|
|
|
ベンダー バリアントはありません。このモジュールは FWK-ONLY です。 |
true |
無効(ビルドエラー) | ||
true |
false |
ベンダー バリアントは VNDK-Private です。共有ライブラリは VNDK APEX にインストールされます。これらをベンダー モジュールで直接使用することはできません。 | |
true |
ベンダー バリアントは VNDK-SP-Private です。共有ライブラリは VNDK APEX にインストールされます。これらをベンダー モジュールで直接使用することはできません。 |
VNDK 拡張機能
VNDK 拡張機能は、追加の API のある VNDK 共有ライブラリです。拡張機能は、バージョンのサフィックスなしで /vendor/lib[64]/vndk[-sp]
にインストールされ、ランタイムに元の VNDK 共有ライブラリをオーバーライドします。
VNDK 拡張機能を定義する
Android 9 以上では、Android.bp
は VNDK 拡張機能をネイティブにサポートします。VNDK 拡張機能をビルドするには、vendor:true
プロパティと extends
プロパティを指定した別のモジュールを定義します。
cc_library { name: "libvndk", vendor_available: true, vndk: { enabled: true, }, } cc_library { name: "libvndk_ext", vendor: true, vndk: { enabled: true, extends: "libvndk", }, }
vendor:true
プロパティ、vndk.enabled:true
プロパティ、extends
プロパティを持つモジュールが VNDK 拡張機能を定義します。
extends
プロパティには、ベースの VNDK 共有ライブラリの名前(または VNDK-SP 共有ライブラリ名)を指定する必要があります。- VNDK 拡張機能または VNDK-SP 拡張機能は、拡張元のベース モジュール名に基づいて命名されます。たとえば、
libvndk_ext
の出力バイナリは、libvndk_ext.so
ではなくlibvndk.so
です。 - VNDK 拡張機能は、
/vendor/lib[64]/vndk
にインストールされます。 - VNDK-SP 拡張機能は、
/vendor/lib[64]/vndk-sp
にインストールされます。 - ベースとなる共有ライブラリには、
vndk.enabled:true
とvendor_available:true
の両方が必要です。
VNDK-SP 拡張機能は、VNDK-SP 共有ライブラリから拡張する必要があります(vndk.support_system_process
は同じである必要があります)。
cc_library { name: "libvndk_sp", vendor_available: true, vndk: { enabled: true, support_system_process: true, }, } cc_library { name: "libvndk_sp_ext", vendor: true, vndk: { enabled: true, extends: "libvndk_sp", support_system_process: true, }, }
VNDK 拡張機能または VNDK-SP 拡張機能は、他のベンダーの共有ライブラリに依存する可能性があります。
cc_library { name: "libvndk", vendor_available: true, vndk: { enabled: true, }, } cc_library { name: "libvndk_ext", vendor: true, vndk: { enabled: true, extends: "libvndk", }, shared_libs: [ "libvendor", ], } cc_library { name: "libvendor", vendor: true, }
VNDK 拡張機能を使用する
ベンダー モジュールが VNDK 拡張機能で定義された追加の API に依存している場合、モジュールはその shared_libs
プロパティにある VNDK 拡張機能の名前を指定する必要があります。
// A vendor shared library example cc_library { name: "libvendor", vendor: true, shared_libs: [ "libvndk_ext", ], } // A vendor executable example cc_binary { name: "vendor-example", vendor: true, shared_libs: [ "libvndk_ext", ], }
ベンダー モジュールが VNDK 拡張機能に依存する場合、VNDK 拡張機能は自動的に /vendor/lib[64]/vndk[-sp]
にインストールされます。モジュールが VNDK 拡張機能に依存しなくなった場合は、CleanSpec.mk
にクリーンするステップを追加して、共有ライブラリを削除してください。次に例を示します。
$(call add-clean-step, rm -rf $(TARGET_OUT_VENDOR)/lib/libvndk.so)
条件付きコンパイル
このセクションでは、次の 3 つの VNDK 共有ライブラリ間の微妙な違い(バリアントの 1 つに対する機能の追加や削除など)に対処する方法を説明します。
- コアバリアント(例:
/system/lib[64]/libexample.so
) - ベンダー バリアント(例:
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so
) - VNDK 拡張機能(例:
/vendor/lib[64]/vndk[-sp]/libexample.so
)
条件付きコンパイラ フラグ
Android ビルドシステムは、デフォルトでベンダー バリアントと VNDK 拡張機能の __ANDROID_VNDK__
を定義します。C プリプロセッサのガードを使ってコードを保護できます。
void all() { } #if !defined(__ANDROID_VNDK__) void framework_only() { } #endif #if defined(__ANDROID_VNDK__) void vndk_only() { } #endif
__ANDROID_VNDK__
だけでなく、異なる cflags
または cppflags
を Android.bp
に指定することも可能です。target.vendor
で指定された cflags
または cppflags
はベンダー バリアントに特化しています。
たとえば、次の Android.bp
は、libexample
と libexample_ext
を定義します。
cc_library { name: "libexample", srcs: ["src/example.c"], vendor_available: true, vndk: { enabled: true, }, target: { vendor: { cflags: ["-DLIBEXAMPLE_ENABLE_VNDK=1"], }, }, } cc_library { name: "libexample_ext", srcs: ["src/example.c"], vendor: true, vndk: { enabled: true, extends: "libexample", }, cflags: [ "-DLIBEXAMPLE_ENABLE_VNDK=1", "-DLIBEXAMPLE_ENABLE_VNDK_EXT=1", ], }
下記は src/example.c
のコードリストです。
void all() { } #if !defined(LIBEXAMPLE_ENABLE_VNDK) void framework_only() { } #endif #if defined(LIBEXAMPLE_ENABLE_VNDK) void vndk() { } #endif #if defined(LIBEXAMPLE_ENABLE_VNDK_EXT) void vndk_ext() { } #endif
この 2 つのファイルに従って、ビルドシステムは以下のエクスポート済みシンボルで共有ライブラリを生成します。
インストール パス | エクスポート済みシンボル |
---|---|
/system/lib[64]/libexample.so |
all 、framework_only |
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so |
all 、vndk |
/vendor/lib[64]/vndk/libexample.so |
all 、vndk 、vndk_ext |
エクスポート済みシンボルの要件
VNDK ABI チェッカーは、VNDK ベンダー バリアントと VNDK 拡張機能の ABI を prebuilts/abi-dumps/vndk
の参照 ABI ダンプと比較します。
- VNDK ベンダー バリアントによってエクスポートされたシンボル(例:
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so
)は、ABI ダンプで定義されているシンボルと同じである必要があります(スーパーセットは不可)。 - VNDK 拡張機能によってエクスポートされたシンボル(例:
/vendor/lib[64]/vndk/libexample.so
)は、ABI ダンプで定義されたシンボルのスーパーセットである必要があります。
VNDK ベンダー バリアントまたは VNDK 拡張機能が上記の要件を満たさない場合、VNDK ABI チェッカーがビルドエラーを発し、ビルドが停止します。
ベンダー バリアントからソースファイルまたは共有ライブラリを除外する
ベンダー バリアントからソースファイルを除外するには、ソースファイルを exclude_srcs
プロパティに追加します。同様に、共有ライブラリがベンダー バリアントにリンクされないようにするには、これらのライブラリを exclude_shared_libs
プロパティに指定します。次に例を示します。
cc_library { name: "libexample_cond_exclude", srcs: ["fwk.c", "both.c"], shared_libs: ["libfwk_only", "libboth"], vendor_available: true, target: { vendor: { exclude_srcs: ["fwk.c"], exclude_shared_libs: ["libfwk_only"], }, }, }
この例では、libexample_cond_exclude
のコアバリアントは fwk.c
と both.c
からのコードを含んでおり、共有ライブラリ libfwk_only
と libboth
に依存しています。libexample_cond_exclude
のベンダー バリアントでは、fwk.c
が exclude_srcs
プロパティにより除外されているため、both.c
からのコードのみ含まれます。同様に、libfwk_only
が exclude_shared_libs
プロパティにより除外されているため、共有ライブラリ libboth
のみに依存します。
VNDK 拡張機能からヘッダーをエクスポートする
VNDK 拡張機能を使用すると、VNDK 共有ライブラリに新しいクラスや関数を追加できます。これらの宣言を独立したヘッダーに保持し、既存のヘッダーを変更しないことをおすすめします。
たとえば、新しいヘッダー ファイル include-ext/example/ext/feature_name.h
を、VNDK 拡張機能 libexample_ext
のために作成します。
- Android.bp
- include-ext/example/ext/feature_name.h
- include/example/example.h
- src/example.c
- src/ext/feature_name.c
次の Android.bp
では、libexample
は include
のみをエクスポートし、libexample_ext
は include
と include-ext
の両方をエクスポートします。これにより、libexample
のユーザーが feature_name.h
を誤って含めることはありません。
cc_library { name: "libexample", srcs: ["src/example.c"], export_include_dirs: ["include"], vendor_available: true, vndk: { enabled: true, }, } cc_library { name: "libexample_ext", srcs: [ "src/example.c", "src/ext/feature_name.c", ], export_include_dirs: [ "include", "include-ext", ], vendor: true, vndk: { enabled: true, extends: "libexample", }, }
拡張機能を独立したヘッダー ファイルに分割できない場合の代替策は、#ifdef
ガードを追加することです。ただし、すべての VNDK 拡張機能ユーザーがその定義フラグを必ず追加するようにしてください。cc_defaults
を定義して cflags
に定義フラグを追加し、共有ライブラリを shared_libs
とリンクすることが可能です。
たとえば、新しいメンバー関数 Example2::get_b()
を VNDK 拡張機能 libexample2_ext
に追加するには、既存のヘッダー ファイルを変更し、#ifdef
ガードを追加する必要があります。
#ifndef LIBEXAMPLE2_EXAMPLE_H_ #define LIBEXAMPLE2_EXAMPLE_H_ class Example2 { public: Example2(); void get_a(); #ifdef LIBEXAMPLE2_ENABLE_VNDK_EXT void get_b(); #endif private: void *impl_; }; #endif // LIBEXAMPLE2_EXAMPLE_H_
libexample2_ext_defaults
という名前の cc_defaults
が、libexample2_ext
のユーザー向けに定義されています。
cc_library { name: "libexample2", srcs: ["src/example2.cpp"], export_include_dirs: ["include"], vendor_available: true, vndk: { enabled: true, }, } cc_library { name: "libexample2_ext", srcs: ["src/example2.cpp"], export_include_dirs: ["include"], vendor: true, vndk: { enabled: true, extends: "libexample2", }, cflags: [ "-DLIBEXAMPLE2_ENABLE_VNDK_EXT=1", ], } cc_defaults { name: "libexample2_ext_defaults", shared_libs: [ "libexample2_ext", ], cflags: [ "-DLIBEXAMPLE2_ENABLE_VNDK_EXT=1", ], }
libexample2_ext
のユーザーは、defaults
プロパティに libexample2_ext_defaults
を含めるだけで構いません。
cc_binary { name: "example2_user_executable", defaults: ["libexample2_ext_defaults"], vendor: true, }
プロダクト パッケージ
Android ビルドシステムでは、変数 PRODUCT_PACKAGES
は、デバイスにインストールする実行可能ファイル、共有ライブラリ、パッケージを指定します。指定したモジュールの推移的な依存関係は、同様に暗黙的にそのデバイスにインストールされます。
BOARD_VNDK_VERSION
が有効の場合、vendor_available
または vndk.enabled
を指定したモジュールは特別な扱いを受けます。フレームワーク モジュールが vendor_available
または vndk.enabled
の指定されたモジュールに依存する場合、コアバリアントが推移的なインストール セットに含まれます。ベンダー モジュールが vendor_available
の指定されたモジュールに依存する場合、ベンダー バリアントが推移的なインストール セットに含まれます。ただし、vndk.enabled
の指定されたモジュールのベンダー バリアントは、ベンダー モジュールで使用されるかどうかにかかわらずインストールされます。
ビルドシステムで依存関係がわからない場合(例: ランタイムに dlopen()
でオープンされる可能性のある共有ライブラリ)、これらのモジュールを明示的にインストールするために PRODUCT_PACKAGES
にそのモジュール名を指定する必要があります。
モジュールに vendor_available
または vndk.enabled
が指定されている場合、モジュール名はそのコアバリアントを意味します。PRODUCT_PACKAGES
にベンダー バリアントを明示的に指定するには、モジュール名に .vendor
サフィックスを追加します。次に例を示します。
cc_library { name: "libexample", srcs: ["example.c"], vendor_available: true, }
この例では、libexample
は /system/lib[64]/libexample.so
を、libexample.vendor
は /vendor/lib[64]/libexample.so
を意味します。/vendor/lib[64]/libexample.so
をインストールするには、libexample.vendor
を PRODUCT_PACKAGES
に追加してください。
PRODUCT_PACKAGES += libexample.vendor