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

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

VNDK ビルドのサポートの例

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

vendor_available:true と vndk.enabled:true の libexample

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

フレームワークの実行可能ファイル /system/bin/foo とベンダーの実行可能ファイル /vendor/bin/barlibexample に依存し、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 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} から使用できます。

VNDK APEX

図 2. VNDK APEX。

モジュールの定義

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

ベンダー モジュール

ベンダー モジュールは、ベンダー固有の実行可能ファイル、またはベンダーのパーティションにインストールする必要のある共有ライブラリです。Android.bp ファイルでは、ベンダー モジュールは、vendor プロパティまたは proprietary プロパティを 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.bp 内の header_libsstatic_libsshared_libs と、Android.mk 内の LOCAL_HEADER_LIBRARIESLOCAL_STATIC_LIBRARIESLOCAL_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_librarycc_library_staticcc_library_sharedcc_library_headers の各モジュール定義が、vendor_availablevndk.enabledvndk.support_system_process の 3 つの VNDK 関連プロパティをサポートします。

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

  • コアバリアントは常にフレームワークのみであり、ベンダー モジュールからはアクセスできない。
  • ベンダー バリアントは、フレームワーク モジュールからは常にアクセスできない。
  • 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})にインストールされる。

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

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 にインストールされます。

false

false

false

ベンダー バリアントはありません。このモジュールは 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: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 または cppflagsAndroid.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.cboth.c からのコードを含んでおり、共有ライブラリ libfwk_onlylibboth に依存しています。libexample_cond_exclude のベンダー バリアントでは、fwk.cexclude_srcs プロパティにより除外されているため、both.c からのコードのみ含まれます。同様に、libfwk_onlyexclude_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 では、libexampleinclude のみをエクスポートし、libexample_extincludeinclude-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.vendorPRODUCT_PACKAGES に追加してください。

PRODUCT_PACKAGES += libexample.vendor