VNDK ビルドシステムのサポート

Android 8.1 以降では、ビルド システムに VNDK サポートが組み込まれています。 VNDK サポートが有効になっている場合、ビルド システムはモジュール間の依存関係をチェックし、ベンダー モジュールのベンダー固有のバリアントをビルドし、それらのモジュールを指定されたディレクトリに自動的にインストールします。

VNDK ビルド サポートの例

この例では、 Android.bpモジュール定義はlibexampleという名前のライブラリを定義します。 vendor_availableプロパティは、フレームワーク モジュールとベンダー モジュールがlibexampleに依存する可能性があることを示します。

libexample Vendor_available:true および vndk.enabled:true

図 1. VNDK サポートが有効になっている

フレームワーク実行可能ファイル/system/bin/fooとベンダー実行可能ファイル/vendor/bin/barどちらもlibexampleに依存しており、 shared_libsプロパティにlibexampleがあります。

libexampleフレームワーク モジュールとベンダー モジュールの両方で使用される場合、 libexampleの 2 つのバリアントがビルドされます。コア バリアント ( libexampleにちなんで命名) はフレームワーク モジュールによって使用され、ベンダー バリアント ( libexample.vendorにちなんで命名) はベンダー モジュールによって使用されます。 2 つのバリアントは異なるディレクトリにインストールされます。

  • コアバリアントは/system/lib[64]/libexample.soにインストールされます。
  • vndk.enabledtrueであるため、ベンダー バリアントは VNDK APEX にインストールされます。

詳細については、 「モジュール定義」を参照してください。

ビルドサポートの構成

製品デバイスの完全なビルド システム サポートを有効にするには、 BOARD_VNDK_VERSIONBoardConfig.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_libsstatic_libs 、および/またはshared_libsを使用して依存関係を (明示的に) 指定する必要があります。

VNDK アペックス

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}から入手できます。

VNDK アペックス

図 2. VNDK APEX

モジュール定義

BOARD_VNDK_VERSIONを使用して Android をビルドするには、 Android.mkまたはAndroid.bpのモジュール定義を修正する必要があります。このセクションでは、さまざまな種類のモジュール定義、いくつかの VNDK 関連モジュール プロパティ、ビルド システムに実装される依存関係チェックについて説明します。

ベンダーモジュール

ベンダー モジュールは、ベンダー パーティションにインストールする必要があるベンダー固有の実行可能ファイルまたは共有ライブラリです。 Android.bpファイルでは、ベンダー モジュールはベンダーまたは独自のプロパティをtrueに設定する必要があります。 Android.mkファイルでは、ベンダー モジュールはLOCAL_VENDOR_MODULEまたはLOCAL_PROPRIETARY_MODULEtrueに設定する必要があります。

BOARD_VNDK_VERSIONが定義されている場合、ビルド システムはベンダー モジュールとフレームワーク モジュール間の依存関係を禁止し、次の場合にエラーを生成します。

  • vendor:trueのないモジュールはvendor:trueのモジュールに依存する、または
  • vendor:trueを持つモジュールは、 vendor:truevendor_available:trueも持たない非llndk_libraryモジュールに依存します。

依存関係チェックは、 Android.bpheader_libsstatic_libs 、およびshared_libs 、およびAndroid.mkLOCAL_HEADER_LIBRARIESLOCAL_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 BOARD_VNDK_VERSION有効な場合、これらのライブラリはこれらのライブラリとリンクします。シンボルは、次の場合にのみスタブ共有ライブラリに含まれます。

  • _PRIVATEまたは_PLATFORMで終わるセクションで定義されていない、
  • #platform-onlyタグがありません。
  • #introduce*タグがないか、タグがターゲットと一致します。

VNDK

Android.bpファイルでは、 cc_librarycc_library_staticcc_library_shared 、およびcc_library_headersモジュール定義は、 vendor_availablevndk.enabled 、およびvndk.support_system_processの 3 つの VNDK 関連プロパティをサポートします。

vendor_availableまたはvndk.enabledtrueの場合、2 つのバリアント ( coreVendor ) がビルドされる可能性があります。コア バリアントはフレームワーク モジュールとして扱われ、ベンダー バリアントはベンダー モジュールとして扱われる必要があります。一部のフレームワーク モジュールがこのモジュールに依存している場合、コア バリアントがビルドされます。一部のベンダー モジュールがこのモジュールに依存している場合、ベンダー バリアントがビルドされます。ビルド システムは、次の依存関係チェックを強制します。

  • コア バリアントは常にフレームワークのみであり、ベンダー モジュールにはアクセスできません。
  • ベンダー バリアントには、フレームワーク モジュールは常にアクセスできません。
  • header_libsstatic_libs 、および/またはshared_libsで指定されるベンダー バリアントのすべての依存関係は、 llndk_libraryか、 vendor_availableまたはvndk.enabledを持つモジュールのいずれかである必要があります。
  • vendor_availabletrueの場合、ベンダー バリアントはすべてのベンダー モジュールにアクセスできます。
  • vendor_availablefalseの場合、ベンダー バリアントは他の VNDK または VNDK-SP モジュールからのみアクセスできます (つまり、 vendor:trueを持つモジュールはvendor_available:falseモジュールをリンクできません)。

cc_libraryまたはcc_library_sharedのデフォルトのインストール パスは、次のルールによって決定されます。

  • コアバリアントは/system/lib[64]にインストールされます。
  • ベンダー バリアントのインストール パスは異なる場合があります。
    • vndk.enabledfalseの場合、ベンダー バリアントは/vendor/lib[64]にインストールされます。
    • vndk.enabledtrueの場合、ベンダー バリアントは VNDK APEX( com.android.vndk.v${VER} ) にインストールされます。

以下の表は、ビルド システムがベンダー バリアントをどのように処理するかをまとめたものです。

ベンダー_利用可能ヴンドク
有効
ヴンドク
サポートと同じプロセス
ベンダーバリアントの説明
true false falseベンダー バリアントはVND のみです。共有ライブラリは/vendor/lib[64]にインストールされます。
true無効(ビルドエラー)
true falseベンダーのバリアントはVNDKです。共有ライブラリは VNDK APEX にインストールされます。
trueベンダーのバリアントはVNDK-SPです。共有ライブラリは VNDK APEX にインストールされます。

false

false

false

ベンダーのバリエーションはありません。このモジュールはFWK のみです。

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:trueextendsプロパティを使用して別のモジュールを定義します。

cc_library {
    name: "libvndk",
    vendor_available: true,
    vndk: {
        enabled: true,
    },
}

cc_library {
    name: "libvndk_ext",
    vendor: true,
    vndk: {
        enabled: true,
        extends: "libvndk",
    },
}

vendor:truevndk.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:truevendor_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 libexamplelibexample_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 allframework_only
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so allvndk
/vendor/lib[64]/vndk/libexample.so allvndkvndk_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に依存します。 fwk.cexclude_srcsプロパティによって除外されているため、 libexample_cond_excludeのベンダー バリアントには、 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/機能名.c

次のAndroid.bpでは、 libexample includeのみをエクスポートしますが、 libexample_ext includeinclude-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_defaultslibexample2_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.vendorPRODUCT_PACKAGESに追加します。

PRODUCT_PACKAGES += libexample.vendor